题目链接: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 "); 59 else if(!can(1)) printf("No Solution "); 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 ",L); 66 } 67 } 68 return 0; 69 }