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;
}