zzuoj 10459: Tutti! 【最小费用最大流】

题目链接:zzuoj 10459: Tutti!

10459: Tutti!
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 12 Solved: 2
[Submit][Status][Web Board]
Description
因为Raywzy计划在清明节去爬泰山,所以他决定在去之前好好的锻炼一下身体,跑步是很好的办法!在zzu内,假设有N个房子,M条十字路口,保证寝室编号为1,实验室编号为N。Raywzy只能从一个十字路口跑向另一个十字路口,街道
之间只在十字路口处相交。
Raywzy的跑步计划是按周期进行的,而且他不喜欢走重复的路线,即每天选择一条不同的路线。除了1和N之外,每个点只能走一次。但是Raywzy十分的瘦弱,所以他想尽可能跑短的路线。现在Raywzy希望你可以为他定一个训练计划。
Raywzy每天的起点是1,目的地是实验室~~
内容与题目无关=w=

Input
数据保证单组
第一行2个数n,m。表示十字路口数和街道数。
接下来m行,每行3个数a,b,c,表示十字路口a和十字路口b之间有条长度为c的单向街道。

Output
2个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长度(即长度和)。

Sample Input
7 10
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
2 5 5
3 6 6
5 7 1
6 7 1
Sample Output
2 11

稍微思考就会发现这是最小费用最大流。。。

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
#include <stack>
#define fi first
#define se second
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int MAXN = 1e4 + 10;
const int INF = 0x3f3f3f3f;
void add(LL &x, LL y) { x += y; x %= MOD; }
struct Edge {
    int from, to, cap, flow, cost, next;
};
Edge edge[MAXN*50];
int head[MAXN], edgenum;
void init() { CLR(head, -1); edgenum = 0; }
void addEdge(int u, int v, int w, int c) {
    Edge E = {u, v, w, 0, c, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
    Edge E1 = {v, u, 0, 0, -c, head[v]};
    edge[edgenum] = E1;
    head[v] = edgenum++;
}
bool vis[MAXN];
int dist[MAXN], pre[MAXN];
bool SPFA(int s, int t) {
    queue<int> Q; CLR(dist, INF); CLR(vis, false); CLR(pre, -1);
    vis[s] = true; dist[s] = 0; 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) {
            Edge E = edge[i];
            if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow) {
                dist[E.to] = dist[u] + E.cost;
                pre[E.to] = i;
                if(!vis[E.to]) {
                    vis[E.to] = true;
                    Q.push(E.to);
                }
            }
        }
    }
    return pre[t] != -1;
}
void MCMF(int s, int t, int &flow, int &cost) {
    flow = cost = 0;
    while(SPFA(s, t)) {
        int Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
            Edge E = edge[i];
            Min = min(Min, E.cap - E.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;
    }
}
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF) {
        init();
        for(int i = 2; i <= n-1; i++) {
            addEdge(i, i+n, 1, 0);
        }
        for(int i = 0; i < m; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            if(u != 1 && u != n) u += n;
            addEdge(u, v, 1, w);
        }
        int flow, cost;
        MCMF(1, n, flow, cost);
        printf("%d %d\n", flow, cost);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值