您的位置:首页 > 其它

codeforces 241 E Flights

2016-07-12 16:57 204 查看

题目大意

一个有向图,规定每条边的边权只能为1或2,要求给出一种方案,使得每条1到n的路径长度都一样。

题解

差分约束系统。

如果一条边不在1到n的路径上,那么就不用考虑它。

于是可以建出一个新图。

对于一条边(a,b),则有

dis(b)−dis(a)⩽2

dis(a)−dib(b)⩽−1

然后跑一边SPFA,判掉负圈,有就是无解。

然后遍历所有的边,注意,只有在1~n的路径上的边,边权大于2或小于1时,才是无解,其他的边可以任意赋值,因为它们对答案无影响。

至于如何构图,我一开始是想dp一下,记录每个点是否可以到n。

我用-1表示未访问,1表示可以,0表示不可以

由于一些点不一定可以到达,所以这些点的dp值始终是-1,然而我在判断是不是在新图中时用的是dp[i]!=0,于是挂掉了,WA了好几次。

当然还可以两边dfs,从起点dfs一遍,终点在反向图上dfs一遍,两个点都可以到达的点才是新图上的点。

贴代码:

两边dfs:

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int M=1005;
struct Edge{
int to,v,nxt;
Edge(int _to=0,int _v=0,int _nxt=0):to(_to),v(_v),nxt(_nxt){}
}edge[M*10];
int etot,n,m,a[M*10],b[M*10];
queue<int>Q;
int cnt[M],dis[M],head[M];
bool mark[M],flag[M];
void add_edge(int a,int b,int c){
edge[etot]=Edge(b,c,head[a]);
head[a]=etot++;
}
int on_the_road[M];
bool SPFA(){
for(int i=2;i<=n;i++)
dis[i]=2000000000;
Q.push(1);
while(!Q.empty()){
int x=Q.front();
Q.pop();
mark[x]=0;
for(int i=head[x];~i;i=edge[i].nxt){
int to=edge[i].to;
if(on_the_road[to]!=2) continue;
if(dis[to]>dis[x]+edge[i].v){
dis[to]=dis[x]+edge[i].v;
if(++cnt[to]>n) return false;
if(!mark[to]){
mark[to]=1;
Q.push(to);
}
}
}
}
return true;
}
void dfs(int x,bool f){
if(flag[x]) return;
flag[x]=1;
on_the_road[x]++;
for(int i=head[x];~i;i=edge[i].nxt)
if((f==1)^(edge[i].v>0)) dfs(edge[i].to,f);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
head[i]=-1;
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i],&b[i]);
add_edge(a[i],b[i],2);
add_edge(b[i],a[i],-1);
}
dfs(1,0);
for(int i=1;i<=n;i++)
flag[i]=0;
dfs(n,1);
if(!SPFA()) puts("No");
else{
for(int j=1;j<=m;j++){
if(on_the_road[b[j]]==2&&on_the_road[a[j]]==2&&(dis[b[j]]-dis[a[j]]<=0||dis[b[j]]-dis[a[j]]>2)){
puts("No");
return 0;
}
}
puts("Yes");
for(int i=1;i<=m;i++){
if(dis[b[i]]-dis[a[i]]<1||dis[b[i]]-dis[a[i]]>2) puts("1");
else printf("%d\n",dis[b[i]]-dis[a[i]]);
}
}
return 0;
}


dp

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int M=1005;
struct Edge{
int to,v,nxt;
Edge(int _to=0,int _v=0,int _nxt=0):to(_to),v(_v),nxt(_nxt){}
}edge[M*10];
int etot,n,m,a[M*10],b[M*10];
queue<int>Q;
int cnt[M],dis[M],head[M];
bool mark[M];
void add_edge(int a,int b,int c){
edge[etot]=Edge(b,c,head[a]);
head[a]=etot++;
}
int on_the_road[M];
bool SPFA(){
for(int i=2;i<=n;i++)
dis[i]=2000000000;
Q.push(1);
while(!Q.empty()){
int x=Q.front();
Q.pop();
mark[x]=0;
for(int i=head[x];~i;i=edge[i].nxt){
int to=edge[i].to;
if(!on_the_road[to]||on_the_road[to]==-1) continue;
if(dis[to]>dis[x]+edge[i].v){
dis[to]=dis[x]+edge[i].v;
if(++cnt[to]>n) return false;
if(!mark[to]){
mark[to]=1;
Q.push(to);
}
}
}
}
return true;
}
int dfs(int x){
if(on_the_road[x]!=-1) return on_the_road[x];
on_the_road[x]=0;
for(int i=head[x];~i;i=edge[i].nxt)
if(edge[i].v>0&&dfs(edge[i].to)) on_the_road[x]=1;
if(x==n) on_the_road[x]=1;
return on_the_road[x];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
on_the_road[i]=head[i]=-1;
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i],&b[i]);
add_edge(a[i],b[i],2);
add_edge(b[i],a[i],-1);
}
dfs(1);
if(!SPFA()) puts("No");
else{
for(int j=1;j<=m;j++){
if(on_the_road[b[j]]>0&&on_the_road[a[j]]>0&&(dis[b[j]]-dis[a[j]]<=0||dis[b[j]]-dis[a[j]]>2)){
puts("No");
return 0;
}
}
puts("Yes");
for(int i=1;i<=m;i++){
if(dis[b[i]]-dis[a[i]]<1||dis[b[i]]-dis[a[i]]>2) puts("1");
else printf("%d\n",dis[b[i]]-dis[a[i]]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息