题意:给出一个有n个点m条边的有向图,现在要从图中删去一些边使得图满足以下条件:
1.图中只有一个入口(s)和一个出口(t)
2.所以边都是单向的(这个原图已经保证了)
3.对入口(s)而言,其出度=入度+1
4.对出口(t)而言,其入度=出度+1
5.对入口(s)、出口(t)以外的点,其入度=出度
重新为每个边建立权值!
1.如果有边(u,v,a,b) 并且a<=b,那么建立边(v,u,1,b-a) sum+=a,如果要恢复此边需花费 b-a 的费用;in[u]++,out[v]++;
2.如果有边(u,v,a,b) 并且a>b,那么建立边(u,v,1,a-b) sum+=b,如果要删除此边需花费 a-b 的费用;
3.另需t和s 建立一条虚边,in[s]++,out[t]++;
最后建立一个超级源点S 和超级汇点T,则如果对于点 i in[i]>out[i] 那么建立边(S,i,in[i]-out[i],0);
相反 建立边(i,T,out[i]-in[i],0);
最小费用最大流后,如果max_flow=到汇点t所有容量只和 答案即为:sum+max_flow;
1.图中只有一个入口(s)和一个出口(t)
2.所以边都是单向的(这个原图已经保证了)
3.对入口(s)而言,其出度=入度+1
4.对出口(t)而言,其入度=出度+1
5.对入口(s)、出口(t)以外的点,其入度=出度
而对图中每条边,保留这条边或者删去这条边都有相应的花费,分别为a、b,求使得该图满足条件的最小花费。
重新为每个边建立权值!
1.如果有边(u,v,a,b) 并且a<=b,那么建立边(v,u,1,b-a) sum+=a,如果要恢复此边需花费 b-a 的费用;in[u]++,out[v]++;
2.如果有边(u,v,a,b) 并且a>b,那么建立边(u,v,1,a-b) sum+=b,如果要删除此边需花费 a-b 的费用;
3.另需t和s 建立一条虚边,in[s]++,out[t]++;
最后建立一个超级源点S 和超级汇点T,则如果对于点 i in[i]>out[i] 那么建立边(S,i,in[i]-out[i],0);
相反 建立边(i,T,out[i]-in[i],0);
最小费用最大流后,如果max_flow=到汇点t所有容量只和 答案即为:sum+max_flow;
否则 impossible;
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define CLR(x,y) memset(x,y,sizeof(x))
#define mp(x,y) make_pair(x,y)
#define eps 1e-9
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
template<class T>
inline bool read(T &n)
{
T x = 0, tmp = 1;
char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
template <class T>
inline void write(T n)
{
if(n < 0)
{
putchar('-');
n = -n;
}
int len = 0,data[20];
while(n)
{
data[len++] = n%10;
n /= 10;
}
if(!len) data[len++] = 0;
while(len--) putchar(data[len]+48);
}
//-----------------------------------
const int M=5010;
const int N=111;
int in[N]; //入度和出度的差
int n,m,s,t;
struct Graph
{
struct node
{
int v,next,w,flow;
node() {};
node(int a,int b,int c,int d)
{
next=a;
v=b;
w=c;
flow=d;
}
} E[2*M];
int head[N],pre[N],dis[N];
int beg,end,flow,cost;
bool h[N];
int path[N];
int NE,NV;
void resize(int n)
{
this->NV=n;
}
void init(int n)
{
NE=0;
NV=n;
memset(head,-1,sizeof(int)*(n+10));
}
void insert(int u,int v,int flow,int w)
{
E[NE]=node(head[u],v,w,flow);
head[u]=NE++;
E[NE]=node(head[v],u,-w,0);
head[v]=NE++;
}
bool update(int u,int v,int w)
{
if(dis[u]+w<dis[v])
{
dis[v]=dis[u]+w;
return true;
}
return false;
}
bool spfa()
{
CLR(pre,-1);
CLR(h,0);
for(int i=0; i<=NV; i++)
dis[i]=INF;
dis[beg]=0;
queue<int> q;
q.push(beg);
while(!q.empty())
{
int u=q.front();
q.pop();
h[u]=0;
for(int i=head[u]; i!=-1; i=E[i].next)
{
int v=E[i].v;
if(E[i].flow>0&&update(u,v,E[i].w))
{
pre[v]=u;
path[v]=i;
if(!h[v])
{
h[v]=1;
q.push(v);
}
}
}
}
if(pre[end]==-1)
return false;
return true;
}
int mincost_maxflow(int s,int t)
{
this->beg=s;
this->end=t;
flow=0,cost=0;
while(spfa())
{
int Min=INT_MAX;
for(int i=end; i!=beg; i=pre[i])
if(Min>E[path[i]].flow)
Min=E[path[i]].flow;
for(int i=end; i!=beg; i=pre[i])
{
E[path[i]].flow-=Min;
E[path[i]^1].flow+=Min;
}
flow+=Min;
cost+=dis[end];
}
return cost;
}
} g;
int main()
{
int T,cas=1;
read(T);
while(T--)
{
read(n),read(m),read(s),read(t);
g.init(n+2);
memset(in,0,sizeof(in));
in[s]++,in[t]--;
int u,v,a,b,ss=0,tt=n+1,sum=0,cnt=0;
for(int i=1;i<=m;i++)
{
read(u),read(v),read(a),read(b);
if(a>=b)
{
g.insert(u,v,1,a-b); // 删除(如果流过则不删)
sum+=b;
}
else
{
g.insert(v,u,1,b-a); // 不删除(如果流过则删除,加一条反边中和入度出度)
sum+=a;
in[u]--,in[v]++;
}
}
for(int i=1;i<=n;i++) // 保留入度,计算出度
{
if(in[i]>0)
g.insert(ss,i,in[i],0);
else
{
g.insert(i,tt,-in[i],0);
cnt+=-in[i];
}
}
sum+=g.mincost_maxflow(ss,tt);
printf("Case %d: ",cas++);
if(g.flow==cnt)
write(sum),putchar('\n');
else
puts("impossible");
}
return 0;
}