【CF#241E】Flights 差分约束

本文介绍 CodeForces 241E 的解题思路及实现细节,针对给定的 DAG 图,需分配边权使所有路径长度相等,采用差分约束系统与 SPFA 算法解决。

AC通道:http://codeforces.com/problemset/problem/241/E

【题目大意】

给定一幅n个节点m条边的无重边的DAG,所有边都从编号小的节点指向编号大的节点,且从节点1出发能到达n.

现要求给每条边分配边权1或2,使得从节点1到n的任意路径长度均相等,判定无解或输出任意方案.

2≤n≤1000,1≤m≤5000.

【题解】

对于给定的点(x,y),它们要满足条件1<=dis[y]-dis[x]<=2

变形得到dis[y]<=dis[x]+2,dis[x]<=dis[y]-1

然后通过dfs标记图中不在从1到n的路径的点

然后就是差分约束的那一套了。

/*************
  CF #241E
  by chty
  2016.11.16
*************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 1010
#define up(i,j,n) for(ll i=j;i<=n;i++)
namespace INIT{
	char buf[1<<15],*fs,*ft;
	inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
	inline ll read(){
		ll x=0,f=1;  char ch=getc();
		while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
		while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
		return x*f;
	}
}using namespace INIT;
struct node{ll y,next,v;}e[5010*2];
ll n,m,len,X[5010],Y[5010],Link[MAXN],check[MAXN],vis[MAXN],dis[MAXN],T[MAXN];
void insert(ll x,ll y,ll v) {e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;}
void dfs(ll x){
	vis[x]=1;
	if(x==n) {check[x]=1; return;}
	for(ll i=Link[x];i;i=e[i].next){
		if(e[i].v<0)  continue;
		if(!vis[e[i].y])  dfs(e[i].y);
		if(check[e[i].y])  check[x]=1;
	}
}
void spfa(){
	memset(vis,0,sizeof(vis));
	memset(dis,127,sizeof(dis));
	queue<ll>q;
	q.push(1); vis[1]=1; dis[1]=0;
	while(!q.empty()){
		ll x=q.front();  q.pop();
		for(ll i=Link[x];i;i=e[i].next){
			if(!check[e[i].y])  continue;
			if(dis[x]+e[i].v<dis[e[i].y]){
				dis[e[i].y]=dis[x]+e[i].v;
				if(!vis[e[i].y]){
					if(T[e[i].y]>n)  {puts("No");return;}
					q.push(e[i].y);
					vis[e[i].y]=1;
					T[e[i].y]++;
				}
			}
		}
		vis[x]=0;
	}
	puts("Yes");
	up(i,1,m) {
		if(dis[Y[i]]-dis[X[i]]==1)  puts("1");
		else puts("2");
	}
}
int main(){
	//freopen(FILE".in","r",stdin);
	//freopen(FILE".out","w",stdout);
	n=read();  m=read();
	up(i,1,m)  {X[i]=read(); Y[i]=read(); insert(X[i],Y[i],2); insert(Y[i],X[i],-1);}
	dfs(1);
	spfa();
	return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值