UVA 11478 Halum(差分约束)

 

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34651

 

【思路】

       差分约束系统。

       设结点u上的操作和为sum[u],则边(u,v)权值为d-sum[v]+sum[u]。对于最小值最大问题我们想到二分答案,设二分值为x,则问题变为判断最小值为x时题目是否存在解。对于权值我们有不等式d-sum[v]+sum[u]>=x  =>  sum[v]<=sum[u]+(d-x),由此可以建立差分约束系统。

       无解:如果最小值为1时依然不成立。

       任意解:如果最小值为R+1时成立。

       否则二分答案取最大值,当图中有负权环时差分约束系统无解即二分答案不成立。

 

【代码】

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<queue>
 5 using namespace std;
 6 
 7 const int maxn = 1000+10;
 8 
 9 int n,m;
10 struct Edge { int u,v,w;
11 };
12 vector<int> G[maxn];
13 vector<Edge> es;
14 void addedge(int u,int v,int w) {
15     es.push_back((Edge){u,v,w});
16     int m=es.size();  G[u].push_back(m-1);
17 }
18 bool spfa() {
19     queue<int> q;
20     int inq[maxn],d[maxn],cnt[maxn];
21     memset(inq,0,sizeof(inq));
22     memset(cnt,0,sizeof(cnt));
23     for(int i=1;i<=n;i++)
24         d[i]=0 , inq[i]=1 , q.push(i);
25     while(!q.empty()) {
26         int u=q.front(); q.pop(); inq[u]=0;
27         for(int i=0;i<G[u].size();i++) {
28             Edge e=es[G[u][i]];
29             int v=e.v;
30             if(d[v]>d[u]+e.w) {
31                 d[v]=d[u]+e.w;
32                 if(!inq[v]) {
33                     inq[v]=1 , q.push(v);
34                     if(++cnt[v]>(n)) return false;
35                 }
36             }
37         }
38     }
39     return true;
40 }
41 bool can(int x) {
42     for(int i=0;i<es.size();i++) es[i].w-=x;
43     bool ans=spfa();
44     for(int i=0;i<es.size();i++) es[i].w+=x;
45     return ans;
46 }
47 
48 int main() {
49     while(scanf("%d%d",&n,&m)==2) {
50         es.clear();
51         for(int i=1;i<=n;i++) G[i].clear();
52         int u,v,w;
53         int L=0,R=0;
54         for(int i=0;i<m;i++) {
55             scanf("%d%d%d",&u,&v,&w);
56             addedge(u,v,w); R=max(R,w);
57         }
58         if(can(R+1)) printf("Infinite\n");
59         else if(!can(1)) printf("No Solution\n");
60         else {
61             while(L<R) {
62                 int M=L+(R-L+1)/2;
63                 if(can(M)) L=M; else R=M-1;
64             }
65             printf("%d\n",L);
66         }
67     }
68     return 0;
69 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值