题目大意:
给出每条边可以承载的最大容量,然后给出连接的边和他们的费用。
求是否可以以最小的费用将指定重量的东西载到对面。
思路:
最小费用最大流。
因为是无向图的证明可以来回走,
只要添加从u到v的边再添加从v到u的边就可以了。
有向图中添加反向边的原因是可以反悔走过的路。
代码:
#include <iostream>
using namespace std;
#include <cstring>
#include <stdio.h>
#include <queue>
const int INF = 0x3f3f3f3f;
const int MAX = 110;
int n,m;
int f;
long long c;
int D,K;
int p[MAX];
int edgenum;
int first[MAX];
int vis[MAX];
long long dis[MAX];//记住要long long
struct node {
int u,v;
long long cost;
int flow;
int ne;
int cap;
}e[50000];
struct node1{
int u,v,w;
}E[5050];
void addedge(int u,int v,int w,int cap) {
e[edgenum].u = u;
e[edgenum].v = v;
e[edgenum].cost = w;
e[edgenum].flow = 0;
e[edgenum].cap = cap;
e[edgenum].ne = first[u];
first[u] = edgenum++;
e[edgenum].u = v;
e[edgenum].v = u;
e[edgenum].cost = -w;
e[edgenum].flow = 0;
e[edgenum].cap = 0;
e[edgenum].ne = first[v];
first[v] = edgenum++;
}
void EK() {
queue<int> q;
c = f = 0;
while(1) {
for(int i = 0; i <= n; i++)
dis[i] = INF;
dis[0] = 0;
memset(p,-1,sizeof(p));
memset(vis,0,sizeof(vis));
q.push(0);
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = first[u];i != -1; i = e[i].ne) {
int v = e[i].v;
if(e[i].cap > e[i].flow &&dis[v] > dis[u] + e[i].cost) {
dis[v] = dis[u] + e[i].cost;
p[v] = i;
if(!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
}
if(dis[n] == INF)
break;
int a = INF;
for(int i = p[n];i != -1; i = p[e[i^1].v])
a = min(a,e[i].cap - e[i].flow);
for(int i = p[n]; i != -1; i = p[e[i^1].v]) {
e[i].flow += a;
e[i^1].flow -= a;
}
c += dis[n] * a;
f += a;
}
}
int main() {
while(scanf("%d %d",&n,&m) != EOF) {
for(int i = 1; i <= m; i++)
scanf("%d %d %d",&E[i].u,&E[i].v,&E[i].w);
scanf("%d %d",&D,&K);
memset(first,-1,sizeof(first));
edgenum = 0;
addedge(0,1,0,D);
//memset(first,-1,sizeof(first));
for(int i = 1; i <= m; i++) {
addedge(E[i].u,E[i].v,E[i].w,K);
addedge(E[i].v,E[i].u,E[i].w,K);
}
EK();
if(f == D)
printf("%lld\n",c);
else
printf("Impossible.\n");
}
return 0;
}

1944

被折叠的 条评论
为什么被折叠?



