目录
题目描述
思路
需要清洁的管道下界为1,
不需要清洁的管道下界为0,
可重复经过的管道上界为正无穷,
不可重复经过的管道上界为1。
算是最小费用流的裸题
最小费跟普通最大流的区别就是遍历图时不能直接bfs, 而是找最短路(费用为权).
在找增广路(最短路)时, 计算各边最小残量, flow[v]=min(flow[u],e[i].f);
返回的最短路径长度,为总流可改进量
然后用最小残量来更新增广路上各边流量, 并把最小残量加进当前流结果.
同时更新最小费, 最小费 += 最小残量*最短路长.
有图示与解释的样例输入1
3 0 1
4 4
1 2 A
2 3 B
3 4 C
4 1 D
5 7
1 2 B
2 3 B
3 1 D
2 4 A
4 3 C
1 5 C
5 2 D
5 7
1 2 B
2 3 B
3 1 C
2 4 A
4 3 D
1 5 C
5 2 D样例输出
4
-1
8
样例说明
样例输入2
6 0 0
5 15
1 3 A
1 3 A
1 5 A
2 3 A
2 4 A
2 5 A
3 1 A
3 2 A
3 4 A
4 1 A
4 4 A
4 5 A
5 2 A
5 2 A
5 3 A
5 15
1 3 B
1 4 B
1 4 B
1 5 B
2 2 B
2 3 B
3 2 B
3 5 B
4 1 B
4 1 B
4 1 B
4 4 B
4 4 B
5 1 B
5 4 B
5 15
1 1 B
1 2 B
1 2 B
1 2 B
1 3 B
1 5 B
2 1 A
2 1 B
2 1 B
2 2 B
2 2 B
3 3 B
3 4 B
4 1 B
5 2 B
5 15
1 1 C
1 3 A
1 3 A
1 5 C
2 1 A
2 1 C
2 3 C
2 4 C
3 2 A
3 2 A
3 2 C
3 2 C
4 1 C
4 4 C
5 3 C
5 15
1 1 B
1 3 B
1 4 D
1 4 D
1 5 B
1 5 D
2 1 B
3 4 D
4 1 D
4 1 D
4 2 D
4 5 D
5 1 B
5 1 B
5 4 D
5 15
1 1 D
1 1 D
1 4 C
1 5 B
2 5 B
3 1 D
3 4 D
4 1 D
4 3 D
4 3 D
4 4 D
4 5 D
5 1 B
5 2 B
5 4 D样例输出
0
0
0
0
0
0
样例输入3
6 0 0
5 15
1 3 A
1 5 A
2 1 A
2 3 A
2 4 A
2 5 A
3 2 A
3 3 A
3 4 A
3 5 A
4 5 A
4 5 A
5 1 A
5 3 A
5 5 A
5 15
1 2 B
1 4 B
1 4 B
2 1 B
2 2 B
2 3 B
2 5 B
3 1 B
3 2 B
4 1 B
4 4 B
4 4 B
5 1 B
5 3 B
5 4 B
5 15
1 1 A
1 1 A
2 5 A
2 5 B
3 2 A
3 2 A
3 2 B
3 2 B
4 1 B
4 3 A
4 4 B
4 5 B
4 5 B
5 3 B
5 4 A
5 15
1 1 A
1 1 A
1 2 A
1 2 A
1 5 A
2 3 A
3 1 A
3 2 C
3 3 A
4 5 C
4 5 C
4 5 C
5 2 C
5 3 C
5 5 A
5 15
1 2 B
2 3 B
2 4 B
2 5 D
3 3 D
3 5 B
4 1 B
4 3 B
4 3 B
4 4 B
4 4 D
5 1 D
5 4 B
5 4 D
5 5 B
5 15
1 3 C
1 4 B
1 5 C
2 3 B
2 5 D
3 1 A
3 2 A
3 3 B
3 4 B
3 5 C
4 3 A
4 3 B
5 2 C
5 3 B
5 3 C样例输出
0
-1
-1
0
-1
0
样例输入4
6 0 1
5 15
1 1 A
1 2 A
1 4 A
1 4 A
1 4 A
2 1 A
2 4 A
3 4 A
4 1 A
4 1 A
4 2 A
4 3 A
4 4 A
4 5 A
5 1 A
5 15
1 3 B
1 3 B
1 4 B
2 1 B
3 1 B
3 1 B
3 4 B
3 5 B
4 3 B
4 4 B
4 5 B
5 2 B
5 3 B
5 5 B
5 5 B
5 15
1 1 B
1 5 B
1 5 B
1 5 B
2 1 B
3 1 B
3 4 B
4 2 B
4 3 A
4 4 B
5 1 B
5 4 B
5 4 B
5 5 B
5 5 B
5 15
1 2 A
1 5 A
2 1 A
2 2 A
2 4 C
3 4 C
4 2 C
4 2 C
4 3 C
4 4 C
4 4 C
4 4 C
4 5 C
5 1 A
5 4 C
5 15
1 2 B
1 3 D
1 5 B
2 2 B
2 3 D
2 4 D
3 1 B
3 1 B
3 2 D
3 3 D
3 3 D
3 5 D
4 3 D
5 1 B
5 3 D
5 15
1 3 B
1 3 C
2 1 D
3 1 D
3 1 D
3 2 D
3 3 D
3 3 D
3 4 D
3 5 B
3 5 D
4 3 D
5 3 B
5 3 B
5 5 D样例输出
15
15
16
5
8
6
数据范围
代码
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 222;
struct node
{
int u,v,f,w,nxt;
node(){}
node(int a,int b,int c,int d,int e):u(a),v(b),f(c),w(d),nxt(e){}
}e[N*N];
int cnt=0,n,m,s0,t0,T,baozi,num=0,sum=0;
int head[N],d[N];
void add_edge(int u,int v,int f,int w)
{
e[cnt] = node(u,v,f,w,head[u]);
head[u] = cnt++;
e[cnt] = node(v,u,0,-w,head[v]);
head[v] = cnt++;
}
int pre[N],flow[N],dis[N];
bool vis[N];
int spfa()
{
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
queue<int> q;
q.push(s0);
flow[s0]=inf;
vis[s0]=1;
dis[s0]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if(e[i].f&&dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
//pre数组记录流入v点的边是i
pre[v]=i;
flow[v]=min(flow[u],e[i].f);
if (!vis[v])
vis[v]=1,q.push(v);
}
}
}
if (pre[t0]==-1) return -1;
return flow[t0];
}
int minCostMaxflow()
{
int fw=0;
int ans=0;
int d;
while((d=spfa())!=-1)
{
fw+=d;
//最小残量加进当前流结果
ans+=dis[t0]*d;
//最小费 += 最小残量*最短路长
int v=t0;
while(v!=s0)
{
e[pre[v]].f-=d;
e[pre[v]^1].f+=d;
v=e[pre[v]].u;
}
}
if (fw!=sum) return -1;
else return ans;
}
int main()
{
ios::sync_with_stdio(false);
int s;
cin>>T>>s>>baozi;
while(T--)
{
cin>>n>>m;
s0=0;//虚拟源点
t0=n+1;//虚拟汇点
cnt=0;//边的条数
sum=0;//需要清扫的道路数目
num=0;//根据需要清扫的道路数目得知必须消耗的包子数
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
int u,v;
char c;
while(m--)
{
cin>>u>>v>>c;
if(c=='A')
{
add_edge(u,v,inf,baozi);
d[u]--;
d[v]++;
num+=baozi;
}
else if(c=='B')
{
d[u]--;
d[v]++;
num+=baozi;
}
else if(c=='C')
add_edge(u,v,inf,baozi);
else
add_edge(u,v,1,baozi);
}
for(int i=1;i<=n;++i)
{
if(d[i]>0)
sum+=d[i],
add_edge(s0,i,d[i],0);
else if (d[i]<0)
add_edge(i,t0,-d[i],0);
}
cout<<minCostMaxflow()+num<<endl;
}
return 0;
}