HDOJ:1533-Going Home(最小费用流)

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

 


解题心得:

  • 第一次写最小费用流的题,去hdoj上找了一个入门级题目,建图比较简单,用了spfa和Dij两种写法。

 

//spfa
#include <bits/stdc++.h> using namespace std; const int maxn = 110*110; struct edge{ int to, cap, dis, rev; edge(int To, int Cap, int Dis, int Rev): to(To), cap(Cap), dis(Dis), rev(Rev) {} }; //感觉这里写得超级智障,懒得改了 struct men { int x,y; }; struct House { int x,y; }; vector <edge> ve[maxn]; vector <men> man; vector <House> house; int n, m, S, T; char maps[maxn][maxn]; void init() { S = 0; man.clear(); house.clear(); for(int i=0;i<maxn;i++) ve[i].clear(); for(int i=1;i<=n;i++) scanf("%s",maps[i]+1); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(maps[i][j] == 'm') { men now; now.x = i; now.y = j; man.push_back(now); } else if(maps[i][j] == 'H') { House temp; temp.x = i; temp.y = j; house.push_back(temp); } } } T = man.size() + house.size() + 1; } void build_adge(int s, int to, int dis) { ve[s].push_back(edge(to, 1, dis, ve[to].size())); ve[to].push_back(edge(s, 0, -dis, ve[s].size()-1)); } void add_adge() { for(int i=0;i<man.size();i++) { build_adge(S, i+1, 0); for(int j=0;j<house.size();j++) { int dis = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y); build_adge(i+1, man.size()+j+1, dis); } } for(int i=0;i<house.size();i++) { build_adge(i+1+man.size(), T, 0); } } int dist[maxn], preve[maxn], prevv[maxn]; bool vis[maxn]; bool SPFA() { memset(preve, 0, sizeof(preve)); memset(vis, 0, sizeof(vis)); memset(prevv, 0, sizeof(prevv)); memset(dist, 0x3f, sizeof(dist)); dist[S] = 0; queue <int> qu; qu.push(S); while(!qu.empty()) { int now = qu.front() ;qu.pop(); vis[now] = false; for(int i=0;i<ve[now].size();i++) { edge &e = ve[now][i]; if(dist[e.to] > dist[now] + e.dis && e.cap > 0) { dist[e.to] = dist[now] + e.dis; prevv[e.to] = now; preve[e.to] = i; if(!vis[e.to]) { qu.push(e.to); vis[e.to] = true; } } } } return dist[T] != 0x3f3f3f3f; } int min_cost_flow() { int ans = 0; while(SPFA()) { for(int v = T; v!=S ; v =prevv[v]) { edge &e = ve[prevv[v]][preve[v]]; e.cap -= 1; ve[v][e.rev].cap += 1; ans += e.dis; } } return ans; } int main() { while(scanf("%d%d",&n,&m) && n+m) { init(); add_adge(); printf("%d\n",min_cost_flow()); } return 0; }

Dij

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
const int maxn = 110*110;

struct edge{
    int to, cap, dis, rev;

    edge(int To, int Cap, int Dis, int Rev):
            to(To), cap(Cap), dis(Dis), rev(Rev) {}
};

struct men {
    int x,y;
};

struct House {
    int x,y;
};

vector <edge> ve[maxn];
vector <men> man;
vector <House> house;
int n, m, S, T, h[maxn];
char maps[maxn][maxn];


void init() {
    S = 0;
    man.clear();
    house.clear();
    memset(h, 0, sizeof(h));
    for(int i=0;i<maxn;i++)
        ve[i].clear();
    for(int i=1;i<=n;i++)
        scanf("%s",maps[i]+1);
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            if(maps[i][j] == 'm') {
                men now;
                now.x = i;
                now.y = j;
                man.push_back(now);
            } else if(maps[i][j] == 'H') {
                House temp;
                temp.x = i;
                temp.y = j;
                house.push_back(temp);
            }
        }
    }
    T = man.size() + house.size() + 1;
}

void build_adge(int s, int to, int dis) {
    ve[s].push_back(edge(to, 1, dis, ve[to].size()));
    ve[to].push_back(edge(s, 0, -dis, ve[s].size()-1));
}

void add_adge() {
    for(int i=0;i<man.size();i++) {
        build_adge(S, i+1, 0);
        for(int j=0;j<house.size();j++) {
            int dis = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
            build_adge(i+1, man.size()+j+1, dis);
        }
    }
    for(int i=0;i<house.size();i++) {
        build_adge(i+1+man.size(), T, 0);
    }
}

int dist[maxn], preve[maxn], prevv[maxn];
bool Dij() {
    memset(preve, 0, sizeof(preve));
    memset(prevv, 0, sizeof(prevv));
    memset(dist, 0x3f, sizeof(dist));
    dist[S] = 0;
    priority_queue <P, vector<P>, greater<P> > qu;
    qu.push(make_pair(0,0));
    while(!qu.empty()) {
        P now = qu.top(); qu.pop();
        int pos = now.second;
        if(dist[pos] < now.first)
            continue;
        for(int i=0;i<ve[pos].size();i++) {
            edge &e = ve[pos][i];
            if(e.cap > 0 && dist[e.to] > dist[pos] + e.dis + h[pos] - h[e.to]) {
                dist[e.to] = dist[pos] + e.dis + h[pos] - h[e.to];
                prevv[e.to] = pos;
                preve[e.to] = i;
                qu.push(make_pair(dist[e.to], e.to));
            }
        }
    }
    return dist[T] != 0x3f3f3f3f;
}

int min_cost_flow() {
    int ans = 0;
    while(Dij()) {
        for(int i=0;i<=T;i++)
            h[i] += dist[i];
        ans += h[T];
        for(int v = T; v!=S ; v =prevv[v]) {
            edge &e = ve[prevv[v]][preve[v]];
            e.cap -= 1;
            ve[v][e.rev].cap += 1;
        }
    }
    return ans;
}

int main() {
    while(scanf("%d%d",&n,&m) && n+m) {
        init();
        add_adge();
        printf("%d\n",min_cost_flow());
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/GoldenFingers/p/9501245.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值