首页 > 代码库 > HAOI2015PG图
HAOI2015PG图
P1857 - 【HAOI2015】PG图
Description
背景
LDN不知道为什么特别喜欢PG,也许是某种原因吧……
有一天,他发明了一个游戏“PG图”。
问题描述
给定一个有向图,每条边都有一个权值。
每次你可以选择一个节点u和一个整数d,把所有以u为终点的边的权值减小d,把所有以u为起点的边的权值加上d。最后要让所有边的权值的最小值为正且尽量大。
Input
输入包含若干组数据。
每组数据第一行为两个整数n和m(n<=500,m<=2700),表示点和边的个数。
以下m行,每行包括3个整数u,v,w,表示u -> v有一条边权为w的边。(1<= u,v<= n, -10000<= w<= 10000)
Output
对于每组数据,输出边权最小值的最大值;
如果无法让所有边权都大于0,输出“No Solution”;
如果边权最小值可以无限大,输出“Infinite”。
Sample Input
2 1
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1
Sample Output
Infinite
Infinite
3
1
Hint
数据范围与约定
对于30%的数据:2<= n<= 10,1<= m<= 100
对于60%的数据:2<= n<= 100,1<= m<=1000
对于100%的数据:2<= n<= 500,1<= m<=2700
Source
图论 , 差分约束
W+sum(a)-sum(b)>=mid ,sum(b)-sum(a)<=W-mid;因此就可以用差分约束来写;
想一下,如果mid可行,那么答案上移,不行,下移,判断行不行,也就是spfa能否跑出来,就是看是否存在负权环,可以用递归版的spfa :
for(int u=1;u<=n;u++) for(int i=head[u];i;i=e[i].net) if(spfa(i)) break; bool spfa(int x) { vis[x]=1; for(int i=head[x];i;i=e[i].net) { int to=e[i].to; if(dis[to]>dis[x]+e[i].w) { if(vis[to]) return 1; dis[to]=dis[x]+e[i].w; if(spfa(to)) return 1; } } return vis[x]=0;// 回溯 }
如果max(r+1)都可以,那么解就是正无穷;1不行,那么无解;
收获 : 首先想到的一定是二分答案,所以不要想d值怎么确定,最后的答案是多少,先设出来,得到一个式子(a -> b) W+sum(a)-sum(b)>=mid ;就很显然用差分约束了;
一定要学会分析,不要急着确定每个d,先列式子,一般是差分约束;
1 /* QYP kuai wo dai ma*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<iomanip> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cstdio> 8 #include<queue> 9 #include<ctime> 10 #include<cmath> 11 #include<stack> 12 #include<map> 13 #include<set> 14 #define rep(i,a,b) for(register int i=a;i<=b;i++) 15 #define ll long long 16 #define re register 17 using namespace std; 18 const int N=510,M=2710; 19 struct Edge{ 20 int to,net,w; 21 }e[M]; 22 int head[N],n,m,num_e; 23 int dis[N]; 24 inline int gi() { 25 re int res=0,f=1; 26 char ch=getchar(); 27 while((ch<‘0‘||ch>‘9‘)&&(ch!=‘-‘)) ch=getchar(); 28 if(ch==‘-‘) ch=getchar(),f=-1; 29 while(ch>=‘0‘&&ch<=‘9‘) res=res*10+ch-‘0‘,ch=getchar(); 30 return res*f; 31 } 32 inline void add(int x,int y,int w) { 33 e[++num_e].to=y,e[num_e].w=w,e[num_e].net=head[x],head[x]=num_e; 34 } 35 bool vis[N]; 36 bool spfa(int x) { 37 vis[x]=1; 38 for(int i=head[x];i;i=e[i].net) { 39 int to=e[i].to; 40 if(dis[to]>dis[x]+e[i].w) { 41 if(vis[to]) return 1; 42 dis[to]=dis[x]+e[i].w; 43 if(spfa(to)) return 1; 44 } 45 } 46 return vis[x]=0; 47 } 48 inline bool check(int x) { 49 rep(u,1,n) 50 for(int i=head[u];i;i=e[i].net) e[i].w-=x; 51 bool flag=1; 52 rep(i,1,n) { 53 memset(dis,0,sizeof(dis)); 54 memset(vis,0,sizeof(vis)); 55 if(spfa(i)) {flag=0;break;} 56 } 57 rep(u,1,n) 58 for(int i=head[u];i;i=e[i].net) e[i].w+=x; 59 return flag; 60 } 61 int main() { 62 freopen("pg.in","r",stdin); 63 freopen("pg.out","w",stdout); 64 while(scanf("%d%d",&n,&m)!=EOF) { 65 memset(head,0,sizeof(head)),num_e=0; 66 int l=0,r; 67 rep(i,1,m) { 68 re int u=gi(),v=gi(),w=gi(); 69 add(u,v,w); 70 r=max(w,r); 71 } 72 if(!check(1)) {puts("No Solution");continue;} 73 else if(check(r+1)) {puts("Infinite");continue;} 74 re int mid=0; 75 while(l<=r) { 76 mid=(l+r)>>1; 77 if(check(mid)) l=mid+1; 78 else r=mid-1; 79 } 80 printf("%d\n",r); 81 } 82 return 0; 83 }
HAOI2015PG图