码迷,mamicode.com
首页 > 其他好文 > 详细

HAOI2015PG图

时间:2017-05-06 22:57:33      阅读:252      评论:0      收藏:0      [点我收藏+]

标签:print   二分答案   break   get   title   freopen   name   set   color   

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

图论 , 差分约束

 
通过设每个点的d值为未知数,由于是最小值最大,所以可以用二分,写出式子(a -> b) 

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图

标签:print   二分答案   break   get   title   freopen   name   set   color   

原文地址:http://www.cnblogs.com/ypz999/p/6818794.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!