hdu 5352 MZL's City 2015多校联合训练赛#5 费用流

MZL's City

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 649    Accepted Submission(s): 225


Problem Description
MZL is an active girl who has her own country.

Her big country has N cities numbered from 1 to N.She has controled the country for so long and she only remebered that there was a big earthquake M years ago,which made all the roads between the cities destroyed and all the city became broken.She also remebered that exactly one of the following things happened every recent M years:

1.She rebuild some cities that are connected with X directly and indirectly.Notice that if a city was rebuilt that it will never be broken again.

2.There is a bidirectional road between city X and city Y built.

3.There is a earthquake happened and some roads were destroyed.

She forgot the exactly cities that were rebuilt,but she only knew that no more than K cities were rebuilt in one year.Now she only want to know the maximal number of cities that could be rebuilt.At the same time she want you to tell her the smallest lexicographically plan under the best answer.Notice that 8 2 1 is smaller than 10 0 1.
 

Input
The first contains one integer T(T<=50),indicating the number of tests.

For each test,the first line contains three integers N,M,K(N<=200,M<=500,K<=200),indicating the number of MZL’s country ,the years happened a big earthquake and the limit of the rebuild.Next M lines,each line contains a operation,and the format is “1 x” , “2 x y”,or a operation of type 3.

If it’s type 3,first it is a interger p,indicating the number of the destoyed roads,next 2*p numbers,describing the p destoyed roads as (x,y).It’s guaranteed in any time there is no more than 1 road between every two cities and the road destoyed must exist in that time.
 

Output
The First line Ans is the maximal number of the city rebuilt,the second line is a array of length of tot describing the plan you give(tot is the number of the operation of type 1).
 

Sample Input
  
  
1 5 6 2 2 1 2 2 1 3 1 1 1 2 3 1 1 2 1 2
 

Sample Output
  
  
3 0 2 1
Hint
No city was rebuilt in the third year,city 1 and city 3 were rebuilt in the fourth year,and city 2 was rebuilt in the sixth year.
 

Source




题目:有三种操作,修城,建边,毁边。

第二第三种操作直接处理边就行。

修城操作:建立一个结点v,先dfs看这次修城可以修哪些城市,然后将这些城市与v建立容量为1,费用为0的边

对于每个修城操作的v建立s到v的边,容量为k,越后面的操作费用越低。费用最好是200的以上的,这样取模就能知道最大流是多少了

对于每个城市建立费用为0,容量为1的边到t。

费用流一遍。与s连的边的使用情况就是答案。因为后面的费用较低,所以能保证字典序最小。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
#define maxn 1000
#define maxm 200000
#define inf 10000000
using namespace std;
int head[maxn],tail;
int queue[maxn],pre[maxn],flag[maxn];
int dist[maxn],maxFlow[maxn];
struct Edge{
    int v,u,next,cost,w;
    Edge(){}//费用,权值
    Edge(int u,int v,int next,int cost,int w):u(u),v(v),next(next),cost(cost),w(w){}
} edge[maxm];
void add_edge(int u,int v,int cost,int w){
    edge[tail] = Edge(u,v,head[u],cost,w);
    head[u] = tail++;
    edge[tail] = Edge(v,u,head[v],-cost,0);
    head[v] = tail++;
}
void init(){
    memset(head,-1,sizeof(head));
    tail=0;
}
int SPFA(int start,int end){
    int i,u,v,front,rear;
    front = rear = 0;
    memset(flag,0,sizeof(flag));
    memset(dist,0x1f,sizeof(dist));
    memset(pre,-1,sizeof(pre));
    dist[start] = 0, dist[end] = inf ,flag[start]=1;
    maxFlow[start] = inf, queue[rear++] = start;
    while(front != rear){//增广
        u = queue[front++];
        if(front >= maxn) front = 0;
        flag[u] = 0;
        for(i = head[u]; i!=-1;i=edge[i].next){
            v=edge[i].v;
      if(edge[i].w&&dist[v]>dist[u]+edge[i].cost){
                dist[v]=dist[u]+edge[i].cost;
        maxFlow[v]=min(edge[i].w,maxFlow[u]);
                pre[v]=i;//记录边下标
                if(!flag[v]){
                    queue[rear++]=v;
                    if(rear>=maxn)rear=0;
                    flag[v] =1;
                }
            }
        }
    }
    return dist[end] != inf;
}
//开始点,结束点
int MFMC(int start,int end){
    int min_cost = 0,v;
    while(SPFA(start,end)){
        v = end;
        while(pre[v]>=0){
            edge[pre[v]].w-=maxFlow[end];
            edge[pre[v]^1].w+=maxFlow[end];
            v=edge[pre[v]].u;
        }//跟新费用
        min_cost+=dist[end]*maxFlow[end];
    }
    return min_cost;
}


int map[207][207];
vector<int> stack;
int check[207];
int n;
void dfs(int u){
    if(check[u]) return;
    check[u] = 1;
    stack.push_back(u);
    for(int i = 1;i <= n; i++){
        if(map[u][i] == 1 && check[i] == 0){
            dfs(i);
        }
    }

}

int main(){
    int m,t,k;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        init();
        memset(map,0,sizeof(map));
        for(int i = 1;i <= n; i++)
            add_edge(i,n+1,1,1);
        int q,u,v,t,cost = n+2;
        for(int i = 0;i < m; i++){
            scanf("%d",&t);
            if(t == 1){
                scanf("%d",&u);
                memset(check,0,sizeof(check));
                stack.clear();
                dfs(u);
                add_edge(0,cost,500000-cost*500,k);
                for(int j = 0;j < stack.size() ;j++){
                   add_edge(cost,stack[j],0,1);
                }
                cost++;
            }
            else if(t == 2){
                scanf("%d%d",&u,&v);
                map[v][u] = map[u][v] = 1;
            }
            else {
                scanf("%d",&q);
                while(q--){
                    scanf("%d%d",&u,&v);
                    map[u][v] = map[v][u] = 0;
                }
            }

        }

        int ans = MFMC(0,n+1);
        stack.clear();
        for(int i = head[0];i != -1; i=edge[i].next){
            stack.push_back(k-edge[i].w);
        }
        printf("%d\n",ans%500);
        int flag = 0;
        for(int i = stack.size() - 1;i >= 0; i--){
            if(i != stack.size()-1) printf(" ");
            printf("%d",stack[i]);
        }
        printf("\n");
    }
    return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值