其他分享
首页 > 其他分享> > Codeforces Round #800 (Div. 1) C. Keshi in Search of AmShZ

Codeforces Round #800 (Div. 1) C. Keshi in Search of AmShZ

作者:互联网

题目链接

对于有向图的问题,先想DAG该怎么做,这点还是没错的。对于DAG,就是一个按照拓扑序的DP,从n出发,每个点考虑删掉几条边即可(因为一定是删掉通往的点最差的那些边)。然后就一直在想有环怎么处理,但似乎不存在正确的解决方案。

这时候就应该考虑dijkstra的思路,即按照答案从小到大更新。沿用这个思路的条件是:每一条边的边权是可计算的,且没有负边。但刚才的DP思路,乍一看似乎每条边不是独立的;但会发现:每一种决策就是以一条边为基准,删去通向更劣的解边,而这个边数又恰好是在dijkstra的过程中可以计算的!!!

其实本质上是:把原本以为需要所有出边指向的点都算出来后,才能算出这个点的答案的问题;通过对DP转移方程的观察,转化为每条边都代表一种解的最短路问题,而这个解的计算恰好是在dijkstra中能够维护的。

对于有向图上的DP类问题,一般先考虑DAG怎么做,然后有两个方向:
1.考虑环(或强连通分量)该如何处理,如果可以特殊处理即可;
2.考虑用dijkstra的思路,按照答案的顺序更新,这用于每条边的贡献是可以在dijkstra的过程中计算的情况(边权有负数的情况用SPFA应该也可)。

留坑:找一些方向1可做的题目(以前肯定做过,印象中是环上DP之类的)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,hd[N],to[N],nx[N],du[N],tt;
void add(int u,int v){
	nx[++tt]=hd[u];
	to[hd[u]=tt]=v;
	du[v]++;
}
struct node{
	int u,d;
	bool operator <(const node& r) const{
		return d>r.d;
	}
};
int d[N];
priority_queue<node>q;
int main()
{
	cin>>n>>m;
	for(int u,v,i=1;i<=m;i++) scanf("%d%d",&v,&u),add(u,v);
	memset(d,0x3f,sizeof(d));
	d[n]=0;
	q.push((node){n,0});
	while(!q.empty()){
		node u=q.top();
		q.pop();
		if(u.d!=d[u.u]) continue;
		for(int e=hd[u.u];e;e=nx[e]){
			int v=to[e];
			if(u.d+du[v]<d[v]){
				d[v]=u.d+du[v];
				q.push((node){v,d[v]});
			}
			du[v]--;
		}
	}
	cout<<d[1]<<endl;
	return 0;
}

标签:Search,DAG,int,tt,Codeforces,dijkstra,Keshi,hd,DP
来源: https://www.cnblogs.com/szsz/p/16467598.html