您的位置:首页 > 理论基础 > 计算机网络

HDU 5352 - MZL's City(网络流‘最小费用流)

2015-08-05 21:45 711 查看
题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5352

题意:

n个点,m条边,每次最多复活k个点。

操作1:u,复活与u相连的点。

操作2:u,v  u和v之间连边。

操作3:cnt 删除cnt条边,有给出起点终点。

求出最多复活城市的个数且输出字典序最小的每次操作1复活的城市个数。

思路:

设每次操作1为点i+n,dfs得到与u点连接的点v,建边(v,i+n),设容量1,费用0;建边(i+n,t),设流量k,费用m-i,操作越在前面,其费用越高,使得后面的操作复活的城市越多,才能得到字典序最小的答案。

跑一次最小费用流,得到的流量为复活的城市总数,遍历一次操作与汇点的连边的流量为每次操作的答案。

AC.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 205;
const int maxm = 505;
int n, m, k;
int tu[maxn][maxn];

int tot, head[maxn+maxm];
struct Edge {
int to, next, cap, flow, cost;
}edge[maxn*maxm];
void addedge(int u, int v, int cap, int cost)
{
edge[tot].to = v;
edge[tot].cap = cap;
edge[tot].cost = cost;
edge[tot].flow = 0;
edge[tot].next = head[u];
head[u] = tot++;

edge[tot].to = u;
edge[tot].cap = 0;
edge[tot].cost = -cost;
edge[tot].flow = 0;
edge[tot].next = head[v];
head[v] = tot++;
}

bool vs[maxn];
int q[maxm];
void dfs(int u, int fa, int cap, int cost)
{
vs[u] = 1;
addedge(u, fa, cap, cost);
for(int i = 1; i <= n; ++i) {
if(!vs[i] && tu[u][i]) {
dfs(i, fa, cap, cost);
}
}
}

int N;
int dis[maxn+maxm], pre[maxn+maxm];
bool vis[maxn+maxm];
bool spfa(int s, int t)
{
queue<int> q;
for(int i = 0; i < N; ++i) {
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty()) {

int u = q.front(); q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t] == -1) return false;
else return true;
}

int solve(int s, int t, int &cost)
{
int flow = 0;
cost = 0;
while(spfa(s, t)) {
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
if(Min > edge[i].cap - edge[i].flow) {
Min = edge[i].cap - edge[i].flow;
}
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
return flow;
}

void init()
{
N = n+m+2;
tot = 0;
memset(head, -1, sizeof(head));
memset(tu, 0, sizeof(tu));
}

int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d %d %d", &n, &m, &k);

init();
int Q = 0;
int s = 0, t = n+m+1;
for(int i = 1; i <= n; ++i) {
addedge(s, i, 1, 0);
}
for(int i = 1; i <= m; ++i) {
int p;
scanf("%d", &p);
if(p == 1) {
Q++;
int u;
scanf("%d", &u);

memset(vs, 0, sizeof(vs));
dfs(u, i+n, 1, 0);

addedge(i+n, t, k, m-i);
q[Q] = tot-2;
}

if(p == 2) {
int u, v;
scanf("%d%d", &u, &v);
tu[u][v] = tu[v][u] = 1;
}

if(p == 3) {
int c, u, v;
scanf("%d", &c);
while(c--) {
scanf("%d%d", &u, &v);
tu[u][v] = tu[v][u] = 0;
}
}
}

int cost;
int flow = solve(s, t, cost);
printf("%d\n", flow);
for(int i = 1; i <= Q; ++i) {
int c = q[i];
printf("%d", edge[c].flow);
if(i == Q) printf("\n");
else printf(" ");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU