CodeForces - 1407E Egor in the Republic of Dagestan(最短路+dp)

题目链接:点击查看

题目大意:给出 n 个点和 m 条边的有向图,每条边的长度为 1 ,有一个属性由 0 或 1 表示,现在需要给每个节点赋值,使得:

  1. 如果点 u 的权值为 0 ,则 u 只能走 ( u , v ) 且这条边的属性为 0 的边
  2. 如果点 u 的权值为 1 ,则 u 只能走 ( u , v ) 且这条边的属性为 1 的边

问如何赋值能让点 1 到点 n 的最短路最大,输出一种构造方案

题目分析:首先设计 dp ,为了契合最短路的模板,在这个题目中我用 d 数组作为 dp 数组,d[ i ][ 0 ] 和 d[ i ][ 1 ] 分别表示 i 点为 0 或 1 时,到达点 n 的最短路,显然比较 d[ i ][ 0 ] 和 d[ i ][ 1 ] 的大小,选较大的为点 i 赋值就能让最短路最大了,当两者相等时,赋值为 0 或 1 都是一样的

然后考虑 dp 的转移,因为我们要求以 n 个点为起点的 d[ i ][ 0 ] 和 d[ i ][ 1 ] ,肯定是不能求 n 次迪杰斯特拉的,又因为所有的 d 数组都是以点 n 为终点的,所以我们不妨将整个图翻转,然后求以点 n 为起点的单源最短路

下面说一下该如何转移状态方程,假如现在有一条由 u 向 v 的边,且该边的属性为 t ,因为我们要使得最短路最大,所以显然要用 max( d[ u ][ 0 ] , d[ u ][ 1 ] ) 向点 v 进行转移,这就是最简单的最短路问题了,因为这个题目中的边权都为 1 ,所以我们可以用 bfs 来代替迪杰斯特拉

有一点需要注意的是,因为每个点有两个属性需要更新,所以每个点可能会被遍历多次,如果像普通迪杰斯特拉那样加一个 vis 限制的话,可能会导致答案错误,所以我们换一种方法来约束,在代码实现中会打上注释,其效果与 vis 标记的效果是一样的

最后的答案显然就是 max( d[ 1 ][ 0 ] , d[ 1 ][ 1 ] ) 了,方案的话按照求出来的数组直接构造即可

代码:
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;

const int N=5e5+100;

vector>node[N];

int dis[N][2],n,m;

void bfs()
{
	memset(dis,inf,sizeof(dis));
	dis[n][0]=dis[n][1]=0;
	queue>q;
	q.push(make_pair(n,0));
	while(q.size())
	{
		int u,w;
		tie(u,w)=q.front();
		q.pop();
		if(max(dis[u][0],dis[u][1])!=w)//用来代替vis的一句话
			continue;
		for(auto t:node[u])
		{
			int v=t.first;
			int type=t.second;
			if(dis[v][type]>max(dis[u][0],dis[u][1])+1)
			{
				dis[v][type]=max(dis[u][0],dis[u][1])+1;
				q.push(make_pair(v,max(dis[v][0],dis[v][1])));
			}
		}
	}
}
 
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	scanf("%d%d",&n,&m);
	while(m--)
	{
		int u,v,c;
		scanf("%d%d%d",&u,&v,&c);
		node[v].emplace_back(u,c);
	}
	bfs();
	int ans=max(dis[1][0],dis[1][1]);
	if(ans==inf)
		ans=-1;
	printf("%d\n",ans);
	for(int i=1;i<=n;i++)
		if(dis[i][0]>=dis[i][1])
			putchar('0');
		else
			putchar('1');

















	return 0;
}

 

你可能感兴趣的:(最短路,动态规划,CodeForces上分)