第一个问题:
费用流中,原图无负环的前提上,为什么增广时的最短路算法不会陷入负环,即为什么增广后的残图不会出现负环?
其实这是一个很浅显的问题,可是我纠结了好长时间,233。
费用流中,原图无负环的前提上,为什么增广时的最短路算法不会陷入负环,即为什么增广后的残图不会出现负环?
其实这是一个很浅显的问题,可是我纠结了好长时间,233。
首先假设残图会出现负环,则其出现负环的原因必然是增广后某些反向弧被加入的残图中。
而增广路肯定是无环的,所以这些反向弧只可能是负环的一部分。
设这些反向弧组成的路径为P,P上各反向弧对应的边组成的路径为P',负环的另一部分组成的路径为Q。
而P成为负环的一部分的前提是P的权值和的绝对值大于Q的权值和。而上述前提的前提是 P' 的权值和大于Q的权值和。
显然,上述前提与我们要寻找关于权值的最短增广路是相矛盾的。
因为如果上述前提成立,那么我们拿Q来替换P'会得到一条关于权值的更短的增广路。
所以,在原图无负环的前提上,增广后的残图中是不会出现负环的。
ISAP
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 6000007
using namespace std;
const int EDGE = 6000000,POINT = 1010;
struct E
{
int u,v,Max,next;
}edge[EDGE];
int head[POINT];
int curr[POINT];
int Top;
void Link(int u,int v,int flow)
{
edge[Top].u = u;
edge[Top].v = v;
edge[Top].Max = flow;
edge[Top].next = head[u];
head[u] = Top++;
}
int dis[POINT],gap[POINT],pre[POINT];
queue<int> q;
void Updata_Dis(int S,int T,int n)
{
memset(dis,-1,sizeof(dis));
memset(gap,0,sizeof(gap));
dis[T] = 0;
gap[0] = 1;
q.push(T);
int f;
while(q.empty() == false)
{
f = q.front();
q.pop();
for(int p = head[f];p != -1;p = edge[p].next)
{
if(dis[edge[p].v] == -1)
{
dis[edge[p].v] = dis[f] + 1;
gap[dis[f]+1]++;
q.push(edge[p].v);
}
}
}
}
int ISAP(int S,int T,int n)
{
memcpy(curr,head,sizeof(curr));
Updata_Dis(S,T,n);
int flow = 0,u = pre[S] = S,p;
while(dis[S] < n)
{
if(u == T)
{
int temp = INF,pos;
for(p = S;p != T;p = edge[curr[p]].v)
{
if(temp > edge[curr[p]].Max)
{
temp = edge[curr[p]].Max;
pos = p;
}
}
for(p = S;p != T;p = edge[curr[p]].v)
{
edge[curr[p]].Max -= temp;
edge[curr[p]^1].Max += temp;
}
flow += temp;
u = pos;
}
for(p = curr[u];p != -1;p = edge[p].next)
{
if(dis[edge[p].v]+1 == dis[u] && edge[p].Max)
break;
}
if(p != -1)
{
curr[u] = p;
pre[edge[p].v] = u;
u = edge[p].v;
}
else
{
if((--gap[dis[u]]) == 0)
break;
int temp = n;
for(p = head[u];p != -1;p = edge[p].next)
{
if(temp > dis[edge[p].v] && edge[p].Max)
{
curr[u] = p;
temp = dis[edge[p].v];
}
}
dis[u] = temp+1;
gap[dis[u]]++;
u = pre[u];
}
}
//printf("%d\n",flow);
return flow;
}
int L[410],R[410];
int Map[410][410];
bool mark[POINT];
bool dfs(int s,int pre)
{
mark[s] = true;
for(int p = head[s] ;p != -1; p = edge[p].next)
{
if(edge[p].v != pre && edge[p].Max)
{
if(mark[edge[p].v] == true || dfs(edge[p].v,s) == false)
return false;
}
}
mark[s] = false;
return true;
}
bool Judge(int n,int m)
{
memset(mark,false,sizeof(mark));
for(int i = 1;i <= n; ++i)
{
if(dfs(i+1,-1) == false)
{
return false;
}
}
return true;
}
int main()
{
int i,j,n,m,k;
//freopen("1002.in","r",stdin);
//freopen("data.out","w",stdout);
while(scanf("%d %d %d",&n,&m,&k) != EOF)
{
memset(head,-1,sizeof(head));
Top = 0;
int ans = 0,sum = 0;
int S = 1,T = 1+n+m+1;
for(i = 1;i <= n; ++i)
{
scanf("%d",&L[i]);
ans += L[i];
Link(S,i+1,L[i]);
Link(i+1,S,0);
}
for(i = 1;i <= m; ++i)
{
scanf("%d",&R[i]);
sum += R[i];
Link(n+i+1,T,R[i]);
Link(T,n+i+1,0);
}
for(i = 1;i <= n; ++i)
{
for(j = 1;j <= m; ++j)
{
Link(i+1,1+n+j,k);
Link(1+n+j,i+1,0);
}
}
if(ans != sum || ans > n*m*k || ISAP(S,T,T) != ans)
{
printf("Impossible\n");
}
else if(Judge(n,m) == false)
{
printf("Not Unique\n");
}
else
{
for(i = 0;i < Top; i += 2)
{
if(edge[i].u != S && edge[i].v != T)
{
Map[edge[i].u - 1][edge[i].v - n-1] = edge[i^1].Max;
}
}
printf("Unique\n");
for(i = 1;i <= n; ++i)
{
for(j = 1;j <= m; ++j)
{
printf("%d",Map[i][j]);
if(j == m)
printf("\n");
else
printf(" ");
}
}
}
}
return 0;
}