zoukankan      html  css  js  c++  java
  • UVA 11478 Halum(用bellman-ford解差分约束)

    对于一个有向带权图,进行一种操作(v,d),对以点v为终点的边的权值-d,对以点v为起点的边的权值+d。现在给出一个有向带权图,为能否经过一系列的(v,d)操作使图上的每一条边的权值为正,若能,求最小边权的最大值。

    不得不说,图论与动态规划的产物实在是神奇!!

    1、既然是“最小值最大”问题,容易想到二分答案。

    2、抽象出数学模型。这个在《训练指南》里写得已经很详细,鄙人还是以自己的理解表达一下。

      这里有两处特别值得学习的地方。一、叠加:假设每个点都对应着一个(v,d)操作,那么对于边u->v来说,受到两个端点的影响,最终的权值为(c+du-dv)。二、抽象:这个没学过差分约束真心想不到。之前想到了二分答案,那么我们假设最终的“最小值最大”为x,那么所有边满足(c+du-dv)>=x,变形后(dv-du)<=(c-x)。由于是第一次做这种类型的题,无法妄下结论,但书上所说到的“最短路中的不等式d[v]<=d[u]+w(u,v)”,很明显,我们常用的的不等式是d[v]>=d[u]+w(u,v)。所以,这里先记住这个模型:形如xj-xi

    <=b,建边i->j,边权为b。(提出疑问:若得到的模型为xi-xj>=b,变形后xj-xi<=-b => 建边i->j,边权为-b)。

      至于书上说的"加源点s",完全不知为何物= =。不过不妨碍我们做题。由于采用二分答案,边权c是变值,处理方式很直白的把所有的边-x,判完负环再做+x就好了。

      为何判负环就可行呢?我们通过二分答案,改变b的值,每次都得到了一个的形如xj-xi<=b的不等式组,当不等式组不成立即说明当前二分的值不成立。举个例子:有个环1->2,2->3,3->1,对应的不等式x2-x1<=ca,x3-x2<=cb,x1-x3<=cc,若这是个负环,说明等式右侧(ca+cb+cc)<0,而等式左侧=0,为恒不等式。所以一旦存在负环,不等式组不成立,差分约束系统无解。

    注意:

    1、先做完特判,再处理其他数据,这点是通用的。(我一开始把判“No Solution”放在二分后面了,TLE。当然现在也不过是飘过时限= =)

      判“Inf”,无环,就不会在同一个圈中两两影响。判“No”要用1而不能是0,因为最后求得是正数。

    2、二分写得时候要注意,要绝对防止 l,r 在相邻两个数之间不变。e.g:第三组样例,l=3,r=4,x作为中间值,当x==3,成立=>l=x;当x==4,不成立=>r=x。死循环了(偶真是弱爆了,明明很简单的问题还要想半天)

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 #include<algorithm>
      5 #define clr(a,m) memset(a,m,sizeof(a))
      6 #define rep(i,a,b) for(int i=a;i<=b;i++)
      7 using namespace std;
      8 
      9 const int MAXN=555;
     10 const int INF =1e8;
     11 
     12 struct Edge{
     13     int u,v,c;
     14 };
     15 
     16 int inq[MAXN],cnt[MAXN],d[MAXN];
     17 vector<Edge>edge;
     18 vector<int>G[MAXN];
     19 
     20 void init(int n)
     21 {
     22     edge.clear();
     23     rep(i,1,n)
     24         G[i].clear();
     25 }
     26 
     27 void add(int u,int v,int c)
     28 {
     29     edge.push_back((Edge){u,v,c});
     30     int m=edge.size();
     31     G[u].push_back(m-1);
     32 }
     33 
     34 double build(int m)
     35 {
     36     int u,v;
     37     int c,up=0;
     38     rep(i,1,m){
     39         scanf("%d%d%d",&u,&v,&c);
     40         up=max(up,c);
     41         add(u,v,c);
     42     }
     43     return up;
     44 }
     45 
     46 bool BF(int st,int n)
     47 {
     48     clr(inq,0);
     49     clr(cnt,0);
     50     queue<int>q;
     51     rep(i,1,n){
     52         if(i==st)d[i]=0;
     53         else d[i]=INF;
     54         q.push(i);
     55     }
     56     while(!q.empty())
     57     {
     58         int u=q.front();q.pop();
     59         inq[u]=false;
     60         int sz=G[u].size();
     61         rep(i,0,sz-1){
     62             Edge e=edge[G[u][i]];
     63             if(d[e.v]>d[u]+e.c){
     64                 d[e.v]=d[u]+e.c;
     65                 if(!inq[e.v]){
     66                     q.push(e.v);
     67                     inq[e.v]=true;
     68                     if(++cnt[e.v]>n)
     69                         return true;
     70                 }
     71             }
     72         }
     73     }
     74     return false;
     75 }
     76 
     77 bool test(int n,int m,int x)
     78 {
     79     rep(i,0,m-1)
     80         edge[i].c-=x;
     81     bool flog=BF(1,n);
     82     rep(i,0,m-1)
     83         edge[i].c+=x;
     84     return flog;
     85 }
     86 
     87 int main()
     88 {
     89     int T,n,m;
     90     while(~scanf("%d%d",&n,&m))
     91     {
     92         init(n);
     93         int up=build(m);
     94 
     95         if(!test(n,m,up+1))
     96             printf("Infinite
    ");
     97         else if(test(n,m,1))
     98             printf("No Solution
    ");
     99         else{
    100             int  l=0,r=up;
    101             while(l<r)
    102             {
    103                 int x=l+(r-l+1)/2;
    104                 if(test(n,m,x))
    105                     r=x-1;
    106                 else
    107                     l=x;
    108             }
    109             printf("%d
    ",l);
    110         }
    111     }
    112     return 0;
    113 }
    View Code

     后记:

    1、书上所说“最短路中的不等式d[v]<=d[u]+w(u,v)”指的是最短路的关系式,而不是松弛操作。表示从起点s->v的最短路恒<=s->u的最短路+w(u,v)。

    2、根据不等式的变形,的确可以自由选择使用最长路还是最短路求解,但两种方法所得的答案不同,具体解释http://www.cnblogs.com/zstu-abc/p/3277305.html

  • 相关阅读:
    MySql多表循环遍历更新
    GridView控件的选择功能,代码实现CheckBox控件的全选、反选以及取消
    使用HTTP POST请求12306网站接口查询火车车次API
    GridView控件的绑定分页功能
    使用HTTP GET请求12306网站接口获取车站名和车站Code
    浅谈从Oracle数据库中取出10条数据的Select语句与Sql Server、MySql的区别
    2022 程序员口语提升指南
    R语言与java整合
    新浪的股票接口 c# (收藏)
    摘记
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3266795.html
Copyright © 2011-2022 走看看