【UVA11478】Halum (最短路解差分约束)

题目:

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

题意:

  给定一个有向图,每条边都有一个权值。每次你可以选择一个结点v和一个整数d,把所有以v为终点的边的权值减小d,把所有以v为起点的边的权值增加d,最后让所有边的权值的最小值大于零且尽量大。

分析:

  因为不同的操作互不影响,因此可以按任意顺序实施这些操作。另外,对于同一个点的多次操作可以合并,因此可以令sum(u)为作用于结点u之上的所有d之和。这样,本题的目标就是确定所有的sum(u),使得操作之后所有边权的最小值尽量大。

  “最小值最大”又让我们想到使用二分答案的方法。二分答案x之后,问题转化为是否可以让操作完毕后每条边的权值均不小于x。对于边a->b,不难发现操作完毕后它的权值为w(a,b)+sum(a)-sum(b),因此每条边a->b都可以列出一个不等式w(a,b)+sum(a)-sum(b)>=x,移项得sum(b)-sum(a)<=w(a,b)-x。这样,我们实际得到一个差分约束系统。

  差分约束系统是指一个不等式组,每个不等式形如xj-xi<=bk,这里的bk是一些事先已知的常数。这个不等式类似于最短路中的不等式d[v]<=d[u]+w(u,v),我们可以用最短路算法求解:对于约束条件xj-xi<=bk,新建一条边i->j,(根据最短路性质可以证明在图无负环的情况下这个不等式是成立的)权值为bk。如果图中有负权环,则差分约束系统无解。

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 510
  9 #define Maxm 4010
 10 #define INF 0xfffffff
 11 
 12 int n,m;
 13 int first[Maxn],dis[Maxn],cnt[Maxn];
 14 bool bq[Maxn],inq[Maxn];
 15 
 16 struct node
 17 {
 18     int x,y,c,cc,next;
 19 }t[Maxm];int len;
 20 
 21 int mymax(int x,int y) {return x>y?x:y;}
 22 
 23 void ins(int x,int y,int cc)
 24 {
 25     t[++len].x=x;t[len].y=y;t[len].cc=cc;
 26     t[len].next=first[x];first[x]=len;
 27 }
 28 
 29 queue<int > q;
 30 
 31 bool spfa(int s)
 32 {
 33     memset(inq,0,sizeof(inq));
 34     memset(dis,63,sizeof(dis));
 35     memset(cnt,0,sizeof(cnt));
 36     while(!q.empty()) q.pop();
 37     dis[s]=0;inq[s]=1;q.push(s);
 38     while(!q.empty())
 39     {
 40         int x=q.front();q.pop();inq[x]=0;
 41         for(int i=first[x];i;i=t[i].next)
 42         {
 43             int y=t[i].y;
 44             if(dis[y]>dis[x]+t[i].c)
 45             {
 46                 dis[y]=dis[x]+t[i].c;
 47                 if(!inq[y])
 48                 {
 49                     q.push(y);
 50                     inq[y]=1;
 51                     if(++cnt[y]>n+1) return 1;
 52                 }
 53             }
 54         }
 55     }
 56     return 0;
 57 }
 58 
 59 bool check(int x)
 60 {
 61     memset(bq,0,sizeof(bq));
 62     for(int i=1;i<=len-n;i++) t[i].c=t[i].cc-x;
 63     if(spfa(n+1)) return 0;
 64     /*for(int i=1;i<=n+1;i++) if(!bq[i])
 65     {
 66         if(spfa(i)) return 0;
 67     }*/
 68     return 1;
 69 }
 70 
 71 void ffind(int l,int r)
 72 {
 73     while(l<r)
 74     {
 75         int mid=(l+r+1)>>1;
 76         if(check(mid)) l=mid;
 77         else r=mid-1;
 78     }
 79     printf("%d
",l);
 80 }
 81 
 82 int main()
 83 {
 84     while(scanf("%d%d",&n,&m)!=EOF)
 85     {
 86         memset(first,0,sizeof(first));
 87         int mx=-INF;len=0;
 88         for(int i=1;i<=m;i++)
 89         {
 90             int x,y,cc;
 91             scanf("%d%d%d",&x,&y,&cc);
 92             ins(x,y,cc);
 93             mx=mymax(cc,mx);
 94         }
 95         for(int i=1;i<=n;i++)
 96         {
 97             ins(n+1,i,0);t[len].c=0;
 98         }
 99         if(check(mx+1)) {printf("Infinite
");continue;}
100         if(!check(1)) {printf("No Solution
");continue;}
101         ffind(1,mx);
102     }
103     return 0;
104 }
[UVA11478]

2016-04-10 15:33:20

原文地址:https://www.cnblogs.com/Konjakmoyu/p/5374271.html