http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2473
You are given a directed graph G(V,E) with a set of vertices and edges. Each edge (i,j) that connects some vertex i to vertex j has an integer cost associated with that edge. As an example of that operation, consider graph G that has three vertices named (1, 2, 3) and two edges. Edge (1, 2) has cost -1, and edge (2,3) has cost 1. The operation Halum(2,-3) operates on edges entering and leaving vertex 2. Thus, edge (1, 2) gets cost -1-(-3)=2 and the edge (2, 3) gets cost 1 + (-3) = -2. Your goal is to apply the Halum function to a graph, potentially repeatedly, until every edge in the graph has at least a certain cost that is greater than zero. You have to maximize this cost.
|
||||
Input | ||||
Two space-separated integers per case: V(V≤500) and E(E≤2700). E lines follow. Each line represents a directed edge using three space-separated integers (u, v, d). Absolute value of cost can be at most 10000. |
||||
Output | ||||
If the problem is solvable, then print the maximum possible value. If there is no such solution print “No Solution”. If the value can be arbitrary large print “Infinite” |
||||
Sample Input | Sample Output | |||
2 1 |
Infinite |
分析:注意,不同的操作互不影响,因此可以按任意的顺序实施这些操作。另外对于同一个节点的多次操作也可合并,因此可以令sum(u),为作用于节点u之上的所有d之和,这样,本题的目标就是确定所有的sum(u),使得操作之后的所有的边权的最小值尽量大。
“最小值最大”又让我们想到了二分答案。二分答案x后,问题转化为是否可以让操作完毕后的每条边的权值均不小于x。对于边a-》b,不难发现操作完毕之后它的权值为w(a,b)+sum(a)-sum(b),一次每条边都可以列出一个不等式w(a,b)+sum(a)-sum(b)>=x,移项得sum(b)-sum(a)<=w(a,b)-x;这样我们实际上就得到了一个差分约束系统。
#include <stdio.h> #include <string.h> #include <iostream> #include <queue> using namespace std; const int INF=9999999999; const int N=503; struct note { int to,w,next; }edge[N*N]; int head[N],ip,m,n; int cnt[N],dis[N],in[N]; void addedge(int u,int v,int w) { edge[ip].to=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++; } void init() { memset(head,-1,sizeof(head)); ip=0; } bool spfa(int s) { queue<int> q; for(int i=0;i<=n;i++) { dis[i]=INF; in[i]=false; cnt[i]=0; } dis[s]=0; in[s]=true; cnt[s]++; q.push(s); while(!q.empty()) { int u=q.front(); in[u]=false; q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(dis[u]+edge[i].w<dis[v]) { dis[v]=dis[u]+edge[i].w; if(!in[v]) { q.push(v); in[v]=true; if(++cnt[v]>=n+1) return false; } } } } return true; } bool jud(int x) { bool flag=1; for(int i=0;i<=n;i++) for(int j=head[i];j!=-1;j=edge[j].next) edge[j].w-=x; if(!spfa(0)) flag=0; for(int i=0;i<=n;i++) for(int j=head[i];j!=-1;j=edge[j].next) edge[j].w+=x; return flag; } int main() { while(~scanf("%d%d",&n,&m)) { init(); int u,v,w; int maxx=-INF; for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); maxx=max(maxx,w); } for(int i=1;i<=n;i++) addedge(0,i,0); if(jud(maxx+1)) printf("Infinite\n"); else if(!jud(1))printf("No Solution\n"); else { int mid,l=1,r=maxx,ans=1; while(l<=r) { mid=(l+r)>>1; if(jud(mid))//小的满足再判断大的是否可以,因为要取大的 { ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); } } return 0; }