P1993 小K的农场 差分约束
题目描述
小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:
- 农场a比农场b至少多种植了c个单位的作物,
- 农场a比农场b至多多种植了c个单位的作物,
- 农场a与农场b种植的作物数一样多。
但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
输入输出格式
输入格式:
第一行包括两个整数 n 和 m,分别表示农场数目和小 K 记忆中的信息数目。
接下来 m 行:
如果每行的第一个数是 1,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至少多种植了 c 个单位的作物。
如果每行的第一个数是 2,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至多多种植了 c 个单位的作物。如果每行的第一个数是 3,接下来有 2 个整数 a,b,表示农场 a 种植的的数量和 b 一样多。
输出格式:
如果存在某种情况与小 K 的记忆吻合,输出“Yes”,否则输出“No”。
输入输出样例
说明
对于 100% 的数据保证:1 ≤ n,m,a,b,c ≤ 10000。
很明显的一道最长路 边也很好建
但是普通的spfa会超时
用dfs的spfa
最长路: 最长路的超级源点权值取0
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define pb push_back #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 0x3f3f3f3 const int N=1000000+5; const int M=10*N; int n; int pos,head[M]; struct Edge { int nex,to,v; }edge[M]; void add(int a,int b,int c) { edge[++pos].nex=head[a]; head[a]=pos; edge[pos].to=b; edge[pos].v=c; } int dis[N]; int vis[N]; int cnt[N]; /* bool spfa() { rep(i,0,n)dis[i]=-inf,vis[i]=0,cnt[i]=0; dis[0]=0; cnt[0]=1; vis[0]=1; queue<int>q; q.push(0); while(!q.empty()) { int u=q.front();q.pop(); vis[u]=0; for(int i=head[u];i;i=edge[i].nex) { int v=edge[i].to; if(dis[v]<dis[u]+edge[i].v) { dis[v]=dis[u]+edge[i].v; if(!vis[v]) { vis[v]=1; if(++cnt[v]>n)return false; q.push(v); } } } } return true; } */ bool spfa(int u) { vis[u]=1; for(int i=head[u];i;i=edge[i].nex) { int v=edge[i].to; if(dis[v]<dis[u]+edge[i].v) { dis[v]=dis[u]+edge[i].v; if(vis[v])return 0; if(!spfa(v))return 0; } } vis[u]=0; return 1; } int main() { int m; RII(n,m); rep(i,1,m) { int x;RI(x);int a,b,c; if(x==1) { RIII(a,b,c); add(b,a,c); } else if(x==2) { RIII(a,b,c); add(a,b,-c); } else { RII(a,b); add(b,a,0); add(a,b,0); } } rep(i,1,n) add(0,i,0),dis[i]=-inf; if(spfa(0)) printf("Yes"); else printf("No"); return 0; }
最短路写法有个奇怪的地方 连源点的时候居然和最长路的写法一样
可能是超级源点都是要往外部连的?
超级源点的权值可以任意 正数
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define pb push_back #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 0x3f3f3f3 const int N=1000000+5; const int M=10*N; int n; int pos,head[M]; struct Edge { int nex,to,v; }edge[M]; void add(int a,int b,int c) { edge[++pos].nex=head[a]; head[a]=pos; edge[pos].to=b; edge[pos].v=c; } int dis[N]; int vis[N]; int cnt[N]; /* bool spfa() { rep(i,0,n)dis[i]=-inf,vis[i]=0,cnt[i]=0; dis[0]=0; cnt[0]=1; vis[0]=1; queue<int>q; q.push(0); while(!q.empty()) { int u=q.front();q.pop(); vis[u]=0; for(int i=head[u];i;i=edge[i].nex) { int v=edge[i].to; if(dis[v]<dis[u]+edge[i].v) { dis[v]=dis[u]+edge[i].v; if(!vis[v]) { vis[v]=1; if(++cnt[v]>n)return false; q.push(v); } } } } return true; } */ bool spfa(int u) { vis[u]=1; for(int i=head[u];i;i=edge[i].nex) { int v=edge[i].to; if(dis[v]>dis[u]+edge[i].v) { dis[v]=dis[u]+edge[i].v; if(vis[v])return 0; if(!spfa(v))return 0; } } vis[u]=0; return 1; } int main() { int m; RII(n,m); rep(i,1,m) { int x;RI(x);int a,b,c; if(x==1) { RIII(a,b,c); add(a,b,-c); } else if(x==2) { RIII(a,b,c); add(b,a,c); } else { RII(a,b); add(b,a,0); add(a,b,0); } } rep(i,1,n) add(0,i,0),dis[i]=inf;//add(i,0,0)反而会错 if(spfa(0)) printf("Yes"); else printf("No"); return 0; }