HDU_2853 && HDU_3315 (最小费用流)

Assignment

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1124    Accepted Submission(s): 583



Problem Description
Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better.
We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij.
We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.
 

Input
For each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
 

Output
For each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.
 

Sample Input
  
  
3 3 2 1 3 3 2 4 1 26 2 2 1 3 2 3 1 2 3 1 2 3 1 2
 

Sample Output
  
  
2 26 1 2
 

Source
 

题意:有N个人分配M个任务(M >= N),一个人只能接受一个任务,同时一个任务只能分配给一个人,每个人做每个任务都有一个效率值 Eij ,现在告诉你初始匹配方案,要求你改动最少的匹配数,得到最大的效率。

分析:最小费用最大流。此题思路并不难,难就难在如何求最少的变更匹配数。这种问题有一个通用的方法来解决,那就是把费用增加一个大于 N 的倍数 K,比如 N = 50,那么 K = 55 即可。然后呢,对于初始匹配连边时,对费用再 -1,那么求最少变更匹配数的时候就是直接等于(-cost % K),最大效率就是(-cost / K)。

建图:

加入超级源点 s (0),使得 s 连向每个人,s -> i,流量为1,费用为0;

加入超级汇点 t (N + M + 1),使得每个任务连向汇点 t,i + N -> t,流量为1,费用为0;

对于人物 i 和 任务 j,连边 i -> j + N,流量为1,如果mission[i] == j,那么费用为 -E[i][j] * K - 1,否则费用为 -E[i][j] * K。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853

代码清单:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

#define end() return 0

typedef long long ll;   
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxn = 100 + 5;
const int INF = 0x7f7f7f7f;

struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int w) : from(u), to(v), cap(c), flow(f), cost(w) {}
};

struct MCMF{
    int n, m, flow, cost;
    vector <Edge> edge; //边数的两倍
    vector <int> G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号
    int inq[maxn]; //是否在队列
    int d[maxn]; //Bellman-Ford
    int p[maxn]; //上一条弧
    int a[maxn]; //可改进量

    void init(int n){
        this -> n = n;
        for(int i = 0; i <=n ; i++) G[i].clear();
        edge.clear();
    }

    void addEdge(int from, int to, int cap, int cost){
        edge.push_back(Edge(from, to, cap, 0, cost));
        edge.push_back(Edge(to, from, 0, 0, -cost));
        m = edge.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BellmanFord(int s, int t, int& flow, int& cost){
        memset(d, INF, sizeof(d));
        memset(inq, 0, sizeof(inq));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

        queue <int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            inq[u] = 0;
            for(int i = 0; i < G[u].size(); i++){
                Edge& e = edge[G[u][i]];
                if(e.cap > e.flow && d[e.to] > d[u] + e.cost){
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if(!inq[e.to]){
                        q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }

        if(d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        for(int u = t; u != s; u = edge[p[u]].from){
            edge[p[u]].flow += a[t];
            edge[p[u]^1].flow -= a[t];
        }
        return true;
    }

    //需要保证初始网络中没有负权圈
    void MincostMaxflow(int s, int t){
        flow = 0, cost = 0;
        while(BellmanFord(s, t, flow, cost));
    }
};

const int maxN = 50 + 5;
const int maxM = 50 + 5;

int N, M, total;
int E[maxN][maxM];
int mission[maxN];

int tail;
MCMF mcmf;

void input(){
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= M; j++){
            scanf("%d", &E[i][j]);
        }
    }
    for(int i = 1; i <= N; i++){
        scanf("%d", &mission[i]);
    }
}

void createGraph(){
    tail = N + M + 1;
    mcmf.init(tail + 1);

    for(int i = 1; i <= N; i++){
        mcmf.addEdge(0, i, 1, 0);
    }

    for(int i = 1; i <= M; i++){
        mcmf.addEdge(i + N, tail, 1, 0);
    }

    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= M; j++){
            if(mission[i] == j)
                mcmf.addEdge(i, j + N, 1, -100 * E[i][j] - 1);
            else
                mcmf.addEdge(i, j + N, 1, -100 * E[i][j]);
        }
    }
}

void solve(){
    createGraph();
    mcmf.MincostMaxflow(0, tail);
    total = 0;
    for(int i = 1; i <= N; i++){
        total += E[i][mission[i]];
    }
    int dif = N - (-mcmf.cost % 100);
    int cnt = -mcmf.cost / 100 - total;
    printf("%d %d\n", dif, cnt);
} 

int main(){
    while(scanf("%d%d", &N, &M) != EOF){
        input();
        solve();
    }end();
}

My Brute

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1060    Accepted Submission(s): 414



Problem Description
Seaco is a beautiful girl and likes play a game called “My Brute”. Before Valentine’s Day, starvae and xingxing ask seaco if she wants to spend the Valentine’s Day with them, but seaco only can spend it with one of them. It’s hard to choose from the two excellent boys. So there will be a competition between starvae and xingxing. The competition is like the game “My Brute”.


Now starvae have n brutes named from S1 to Sn and xingxing’s brutes are named from X1 to Xn. A competition consists of n games. At the beginning, starvae's brute Si must versus xingxing’s brute Xi. But it’s hard for starvae to win the competition, so starvae can change his brutes’ order to win more games. For the starvae’s brute Si, if it wins the game, starvae can get Vi scores, but if it loses the game, starvae will lose Vi scores. Before the competition, starvae’s score is 0. Each brute can only play one game. After n games, if starvae’s score is larger than 0, we say starvae win the competition, otherwise starvae lose it.

It’s your time to help starvae change the brutes’ order to make starvae’s final score be the largest. If there are multiple orders, you should choose the one whose order changes the least from the original one. The original order is S1, S2, S3 … Sn-1, Sn, while the final order is up to you.

For starvae’s brute Si (maybe this brute is not the original brute Si, it is the ith brute after you ordered them) and xingxing’s brute Xi, at first Si has Hi HP and Xi has Pi HP, Si’s damage is Ai and Xi’s is Bi, in other words, if Si attacks, Xi will lose Ai HP and if Xi attacks, Si will lose Bi HP, Si attacks first, then it’s Xi’s turn, then Si… until one of them’s HP is less than 0 or equal to 0, that, it lose the game, and the other win the game.

Come on, starvae’s happiness is in your hand!
 

Input
First line is a number n. (1<=n<=90) Then follows a line with n numbers mean V1 to Vn. (0<Vi<1000) Then follows a line with n numbers mean H1 to Hn. (1<=Hi<=100)Then follows a line with n numbers mean P1 to Pn. (1<=Pi<=100) Then follows a line with n numbers mean A1 to An.(1<=Ai<=50) Then follows a line with n numbers mean B1 to Bn. (1<=Bi<=50) A zero signals the end of input and this test case is not to be processed.
 

Output
For each test case, if starvae can win the competition, print the largest score starvae can get, and then follow a real percentage means the similarity between the original order and the final order you had changed, round it to three digits after the decimal point. If starvae can’t win the competition after changing the order, please just print “Oh, I lose my dear seaco!” Maybe the sample can help you get it.
 

Sample Input
  
  
3 4 5 6 6 8 10 12 14 16 7 7 6 7 3 5 3 4 5 6 6 8 10 12 14 16 5 5 5 5 5 5 0
 

Sample Output
  
  
7 33.333% Oh, I lose my dear seaco!
 

Author
starvae
 

Source
 
分析:同上。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3315

代码清单:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

#define end() return 0

typedef long long ll;   
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxN = 1000 + 5;
const int maxn = 2000 + 5;
const int INF = 0x7f7f7f7f;

int N;
int V[maxN];
int H[maxN];
int P[maxN];
int A[maxN];
int B[maxN];
int S,X;

struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int w) : from(u), to(v), cap(c), flow(f), cost(w) {}
};

struct MCMF{
    int n, m, flow, cost;
    vector <Edge> edge; //边数的两倍
    vector <int> G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号
    int inq[maxn]; //是否在队列
    int d[maxn]; //Bellman-Ford
    int p[maxn]; //上一条弧
    int a[maxn]; //可改进量
    

    void init(int n){
        this -> n = n;
        for(int i = 0; i <=n ; i++){
            G[i].clear();
           
        }
        edge.clear();
    }

    void addEdge(int from, int to, int cap, int cost){
        edge.push_back(Edge(from, to, cap, 0, cost));
        edge.push_back(Edge(to, from, 0, 0, -cost));
        m = edge.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BellmanFord(int s, int t, int& flow, int& cost){
        memset(d, INF, sizeof(d));
        memset(inq, 0, sizeof(inq));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

        queue <int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            inq[u] = 0;
            for(int i = 0; i < G[u].size(); i++){
                Edge& e = edge[G[u][i]];
                if(e.cap > e.flow && d[e.to] > d[u] + e.cost){
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if(!inq[e.to]){
                        q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }

        if(d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        for(int u = t; u != s; u = edge[p[u]].from){
            edge[p[u]].flow += a[t];
            edge[p[u]^1].flow -= a[t];
        }
        return true;
    }

    //需要保证初始网络中没有负权圈
    void MincostMaxflow(int s, int t){
        flow = 0, cost = 0;
        while(BellmanFord(s, t, flow, cost));
    }
};

int tail;
MCMF mcmf;

void input(){
    for(int i = 1; i <= N; i++){
        scanf("%d", &V[i]);
    }
    for(int i = 1; i <= N; i++){
        scanf("%d", &H[i]);
    }
    for(int i = 1; i <= N; i++){
        scanf("%d", &P[i]);
    }
    for(int i = 1; i <= N; i++){
        scanf("%d", &A[i]);
    }
    for(int i = 1; i <= N; i++){
        scanf("%d", &B[i]);
    }
}

void createGraph(){
    tail = N + N + 1;
    mcmf.init(tail + 1);
    for(int i = 1; i <= N; i++){
        mcmf.addEdge(0, i, 1, 0);
        mcmf.addEdge(i + N, tail, 1, 0);
    }
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= N; j++){

            S = H[i] % B[j] == 0 ? H[i] / B[j] : H[i] / B[j] + 1;
            X = P[j] % A[i] == 0 ? P[j] / A[i] : P[j] / A[i] + 1;
            if(S >= X){
                if(i != j) 
                    mcmf.addEdge(i, j + N, 1, - V[i] * 1000);
                else
                    mcmf.addEdge(i, j + N, 1, - V[i] * 1000 - 1);

            }
            else{
                if(i != j)
                    mcmf.addEdge(i, j + N, 1, V[i] * 1000);
                else
                    mcmf.addEdge(i, j + N, 1, V[i] * 1000 - 1);
            }
        }
    }
}

void solve(){
    createGraph();
    mcmf.MincostMaxflow(0, tail);
    if(mcmf.cost / 1000 >= 0){
        printf("Oh, I lose my dear seaco!\n");
    }
    else{
        printf("%d %.3lf%%\n", -mcmf.cost / 1000, -mcmf.cost % 1000 *100.0 /(double)N);
    }
}

int main(){
    while(scanf("%d", &N) != EOF && N){
        input();
        solve();
    }end();
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值