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;
}
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 1568
- HDU1290
- HDU1568(Fobonacci公式)
- HDU ACM Step 2.2.2 Joseph(约瑟夫环问题)
- HDU 1405
- HDU 1297
- hdu 1205
- hdu 2087
- hdu 1016
- HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
- HDU 1000
- HDU 1001
- HDU 1622 Trees On The Level
- HDU 1063 Exponentiation
- Hdu5033
- HDU 1166 敌兵布阵
- HDU Rightmost Digit
- hdu 1002
- 贪心 hdu 1003
- hdu 1004