uva 11478 最短路徑問題(負環,差分約束系統)

life4711發表於2014-07-08

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.
 
Define the operation Halum(v, d) to operate on a vertex v using an integer d as follows: subtract d from the cost of all edges that enter v and add d to the cost of every edge that leaves v.

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
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1


Infinite
Infinite
3
1


題目大意:給定一個有向圖,每條邊都有一個權值。每次你可以選擇一個節點v,和一個整數d把所有的以v為終點的邊的權值減小d,把所有的邊的權值減小d,把所有的以v為起點的邊的權值增加d,最後要讓所有的邊權的最小值非負且最大,輸出滿足這種情況的d的最大值。如果無法讓所有邊權都非負,輸出“No Solution”,如果邊權可以任意大那麼輸出“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;
}


相關文章