【Halum操作-UVA 11478】

·英文题,述大意:
      输入有向图一个(什么边的端点啊,边权啊)。每次可以选择一个节点和一个整数,然后把这个结点的出边边权加上该整数,入边边权减去该整数,目标:使得所有边的最小值非负且尽量大。

·分析:

      修改结点周围的边权,题目中既没有限制次数,也没有规定在意先后顺序,这启示我们,每一个操作的效果是可以叠加的(同时就不分先后),所以可以将题目简化为:每一个节点只用一个整数操作一次。

      差分约束的思想运用:如果我们设num(u)表示给节点u施加的那个整数值。则对于有向边(u,v)(权值为W),那么最终该边的边权为:

        W'=W+num(u)-num(v)

读题目最后一句话,可以体会到这是一个美妙的二分。如果当前二分的值是X,表示最小边权。那么对于每一条边,都满足这个式子:

        W+num(u)-num(v)>=X

=>   num(v)-num(u)<=W-X

由于W-X在此时为定值,设P=W-X那么这些不等式都可以统一描述为:左边小于等于右边,左边两个节点信息之差,右边是一个定值。

扭一扭,泡一泡:那么原式为:num(v)<=num(u)+P

·然后这和最短路的if()中的东西是一样的,所以用这些元素依葫芦画瓢地建图(奥,这道题是帮你建好了的……)如果当前二分的X不符合条件,会出现什么情况————出现负环。

·为什么是出现负环就代表不能使所有不等式同时成立呢?

举例说明:(考虑一种建图状态)

image

如果将①③式相加,则会又得到一个关于b,c的不等式:

   sum(c)-sum(b)>=7

该式子不幸地与②式矛盾。

总结归纳地说:只要一坨”连连不等式”(即图中一个环)右边的数值加起来的和为负数(这不是说每个值都是负数),那么对于任意其中点对{m,n},在原有的一个关于它们的不等式的基础上,可以通过其他等式相加再构造一个关于它俩的不等式中,必存在至少一组矛盾(一正一负,绝对爆炸)。所以负环就是不等式组不成立的直接表现。

·最后一个小提醒:在进行SPFA之前,该选谁作为起点呢?反正大家都是平等的,就一同压入队列吧。

 

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<queue>
 4 #include<cstring>
 5 #define go(i,a,b) for(int i=a;i<=b;i++)
 6 #define fo(i,a,x) for(int i=a[x],v=e[i].v;~i;i=e[i].next,v=e[i].v)
 7 #define inf 1000000000
 8 #define mem(a,b) memset(a,b,sizeof(a))
 9 using namespace std;const int N=503;struct E{int v,next,w;}e[N*80]; 
10 int n,m,head[N],k,max_W=-inf,ans,d[N],update_times[N];
11 void ADD(int u,int v,int w){e[k]=(E){v,head[u],w};head[u]=k++;}
12 bool SPFA(int x)
13 {
14     queue<int>q;bool inq[N]={0};
15     go(i,1,n)d[i]=update_times[i]=0,q.push(i),inq[i]=1;
16     
17     while(!q.empty()){int u=q.front();q.pop();inq[u]=0;
18     fo(i,head,u)if(d[u]+e[i].w-x<d[v]){d[v]=d[u]+e[i].w-x;
19         if(!inq[v]){q.push(v);inq[v]=1;
20         if(++update_times[v]>n+1)return 0;}}}return 1;
21 }
22 int main(){while(~scanf("%d%d",&n,&m))
23 {
24     mem(head,-1);k=0;ans=-1;
25     go(i,1,m){int u,v,w;scanf("%d%d%d",&u,&v,&w);
26     max_W=max(max_W,w);ADD(u,v,w);}
27     
28     int l=1,r=max_W+1,mid;
29     while(l<=r)mid=l+r>>1,SPFA(mid)?ans=mid,l=mid+1:r=mid-1;
30         
31     if(ans==max_W+1){printf("Infinite\n");continue;}
32     if(ans==-1){printf("No Solution\n");continue;}
33     printf("%d\n",ans);
34 }return 0;}//Paul_Guderian

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

已经忘了回去的道路,走入独自一人的碎梦。————汪峰《碎梦》

转载于:https://www.cnblogs.com/Paul-Guderian/p/6821557.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值