| Time Limit: 2000MS | Memory Limit: 32768K | |
| Total Submissions: 24008 | Accepted: 12534 |
Description
An example is in figure 1. The label x/y of power station u shows that p(u)=x and p max(u)=y. The label x/y of consumer u shows that c(u)=x and c max(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and l max(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6.
Input
Output
Sample Input
2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20
7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7
(3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5
(0)5 (1)2 (3)2 (4)1 (5)4
Sample Output
15 6
Hint
Source
第一道网络流题目,用的是EK算法。。。1600+ms,比较慢
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define maxn 150
#define inf 0x3f3f3f3f
int first[maxn], top;
int next[maxn*maxn], cap[maxn*maxn],rev[maxn*maxn], to[maxn*maxn];
void add(int u, int v, int c) //有向图
{
to[top] = v, next[top] = first[u];
cap[top] = c, rev[top] = top+1;
first[u] = top++;
to[top] = u, next[top] = first[v];
cap[top] = 0, rev[top] = top-1;
first[v] = top++;
}
int vis[maxn]; //遍历时检查每个点是否搜索过
int pre[maxn]; //pre[v],无权最短路中v的前一个点
int pre_edge[maxn]; //pre_edge[v], 无权最短路中连接v的边
int f[maxn]; //f[v],残余网络中到点v的最大流量
int bfs(int s, int t) //bfs找增广路
{
queue<int> que;
que.push(s);
pre[s] = -1;
vis[s] = 1;
f[s] = inf;
while(!que.empty()){
int u = que.front();
que.pop();
int v;
for(int i = first[u]; i !=-1; i = next[i]){
v = to[i];
if(vis[v] || !cap[i]) continue;
f[v] = min(f[u], cap[i]);
que.push(v);
vis[v] = 1;
pre[v] = u, pre_edge[v] = i;
if(v == t){
while(v != s){
cap[pre_edge[v]] -= f[t];
cap[rev[pre_edge[v]]] += f[t];
v = pre[v];
}
return f[t];
}
}
}
return 0;
}
int ek_max_flow(int s, int t) //ek算法求最大流
{
int ret = 0, f;
while(1){
memset(vis, 0, sizeof(vis));
f = bfs(s, t); //查找增广路
if(!f) break;
ret += f;
}
return ret;
}
int value[5];
void convert(char *str)
{
int len = strlen(str);
int val = 0;
int cnt = 0;
for(int i = 1; i < len; i++){
if(str[i] == ',' || str[i] == ')'){
value[cnt++] = val;
val = 0;
}
else
val = val*10+str[i]-'0';
}
value[cnt] = val;
}
int main()
{
int s, t;
int n, m, np, nc;
char str[100];
int u,v,z;
while(~scanf("%d%d%d%d", &n, &np, &nc, &m)){
memset(first, -1, sizeof(first));
top = 0;
for(int i = 0; i < m; i++){
scanf("%s", str);
convert(str);
add(value[0], value[1], value[2]);
}
for(int i = 0; i < np; i++){
scanf("%s", str);
convert(str);
add(n+1, value[0], value[1]); //n+1为增加的超级源点
}
for(int i = 0; i < nc; i++){
scanf("%s", str);
convert(str);
add(value[0], n+2, value[1]); //n+2为增加的超级汇点
}
printf("%d\n", ek_max_flow(n+1, n+2));
}
return 0;
}
学完Dinic算法再来做一遍,只要63ms。。。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
#define maxn 150
#define inf 0x3f3f3f3f
struct edge
{
edge(int a, int b, int c){to=a; cap = b; rev = c;}
int to, cap, rev;
};
vector<edge> g[maxn];
void add(int u, int v, int c) //有向图
{
g[u].push_back(edge(v, c, g[v].size()));
g[v].push_back(edge(u, 0, g[u].size()-1));
}
int level[maxn];
void bfs(int s)
{
memset(level, -1, sizeof(level));
level[s] = 0;
queue<int> que;
que.push(s);
while(!que.empty()){
int u = que.front(); que.pop();
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i].to, cap = g[u][i].cap;
if(level[v] < 0 && cap > 0){
level[v] = level[u]+1;
que.push(v);
}
}
}
}
int cur[maxn];
int dfs(int u, int t, int f)
{
if(u == t) return f;
for(int &i = cur[u]; i < g[u].size(); i++){
int v = g[u][i].to, &cap = g[u][i].cap, rev = g[u][i].rev;
if(level[v] == level[u]+1 && cap>0){
int tmp = dfs(v, t, min(cap, f));
if(tmp>0){
cap -= tmp;
g[v][rev].cap += tmp;
return tmp;
}
}
}
return 0;
}
int Dinic(int s, int t)
{
int flow = 0;
while(1){
bfs(s);
if(level[t] < 0) return flow;
int f;
memset(cur, 0, sizeof(cur));
while((f = dfs(s, t, 0x3f3f3f3f))) flow += f;
}
}
int value[5];
void convert(char *str)
{
int len = strlen(str);
int val = 0;
int cnt = 0;
for(int i = 1; i < len; i++){
if(str[i] == ',' || str[i] == ')'){
value[cnt++] = val;
val = 0;
}
else
val = val*10+str[i]-'0';
}
value[cnt] = val;
}
int main()
{
int s, t;
int n, m, np, nc;
char str[100];
int u,v,z;
while(~scanf("%d%d%d%d", &n, &np, &nc, &m)){
for(int i = 0; i < maxn; i++) g[i].clear();
for(int i = 0; i < m; i++){
scanf("%s", str);
convert(str);
add(value[0], value[1], value[2]);
}
for(int i = 0; i < np; i++){
scanf("%s", str);
convert(str);
add(n+1, value[0], value[1]); //n+1为增加的超级源点
}
for(int i = 0; i < nc; i++){
scanf("%s", str);
convert(str);
add(value[0], n+2, value[1]); //n+2为增加的超级汇点
}
printf("%d\n", Dinic(n+1, n+2));
}
return 0;
}
299



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



