UVa(12821),MCMF

题目链接:https://uva.onlinejudge.org/external/128/12821.pdf

比赛的时候,准备用最短路来做,存两张图,做两次最短路,本来还觉得第二张图的设计很好的,很不错,结果过了好多案例,还是莫名其妙的WA了。

完了之后,听阳哥说,直接MCMF啊,当时我就傻逼了,主要是我MCMF的题目做少了,不会想到是MCMF。

这里: 每条边的容量是1,花费是边权,然后是超级源点和汇点,容量是2,花费是0。

模板来自刘汝佳,改了Bellman-Ford,用的是SPFA.

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 600;
struct Edge
{
    int from,to,cap,flow,cost;
    Edge() {}
    Edge(int a,int b,int c,int d,int e):from(a),to(b),cap(c),flow(d),cost(e) {}
};
struct MCMF
{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> g[maxn];
    int inq[maxn];
    int d[maxn];
    int p[maxn];
    int a[maxn];

    void init(int n)
    {
        this->n =n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void addedge(int from,int to,int cap,int cost)
    {
        Edge e1= Edge(from,to,cap,0,cost), e2= Edge(to,from,0,0,-cost);
        edges.push_back(e1);
        edges.push_back(e2);
        m=edges.size();
        g[from].push_back(m-2);
        g[to].push_back(m-1);
    }
    bool spfa(int s,int t, int & flow,int & cost)
    {
        for(int i=0; i<n; i++)
            d[i]=INF;
        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 = edges[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+=a[t]*d[t];
        for(int u=t; u!=s; u=edges[p[u]].from)
        {
            edges[p[u]].flow +=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }

    int  MincostMaxflow(int s,int t)
    {
        int flow=0,cost =0;
        while(spfa(s,t,flow,cost));
        return cost;
    }
} sol;

int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int n,m,cas=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int s=0,t=n+1;
        sol.init(n+2);
        while(m--)
        {
            int u,v,c,ad;
            scanf("%d%d%d%d",&u,&v,&c,&ad);
            sol.addedge(u,v,1,c);
            sol.addedge(u,v,1,c+ad);
        }
        sol.addedge(s,1,2,0);
        sol.addedge(n,t,2,0);
        printf("Case %d: %d\n",cas++,sol.MincostMaxflow(s,t));
    }
}
时间: 2024-11-08 23:19:24

UVa(12821),MCMF的相关文章

UVa 1608,Non-boring sequences

好诡异的一个题啊 紫书上关于从左边找还是从两边往中间找的讨论没有看懂,怎么一下就找到唯一的元素了(⊙_⊙?) 方法就是用的书上讲的方法,类似于uva 11572,不过这个题需要预处理存下两边的最近的相同数的位置 for (int i=1;i<=n;i++) { prev[i]=r[a[i]]; next[prev[i]]=i; r[a[i]]=i;}//记录元素a[i]上次出现的位置,因为是从左向右遍历,所以上次出现的位置正好是prev[i]要求的 //prev[i],与 i位置的元素 相同的左

uva 11825 ,Hacker&#39;s Crackdown 状态压缩 dp

// uva 11825 Hacker's Crackdown // // 题目意思看了很久才看懂,有n台计算机,有n种服务,每台计算机上运行所有 // 的服务,并且其中有的计算机与某些计算机相互邻接,对于每台计算机, // 你可以选择一项服务,停止这项服务,则与它邻接的计算机的该服务也停止了 // 你的目的是让经量多的服务完全瘫痪 // // 换而言之,这个问题就是在n个集合中(p[1]....p[n])分成尽量多的组数,使得每组 // 的并集等于全集(即所有的n台电脑都停止)... // /

POJ 1504,ZOJ 2001,UVA 713, Adding Reversed Numbers,错误,已找到错误

------------------------------------------------------------ 以此题警告自己: 总结, 1.在数组的使用时,一定别忘了初始化 2.在两种情况复制代码时,一定要小心,注意修改变量名,一不留神就会带来不可估量的后果,一定要仔细挨着一个一个变量的修改,别跳着看着哪个变量就改哪一个变量! (这个题目中,就是复制了一下,代码,ca,我找了一下午的错....还好终于找到了,一个字母的错,) -----------------------------

Uva 10806 来回最短路,不重复,MCMF

题目链接:https://uva.onlinejudge.org/external/108/10806.pdf 题意:无向图,从1到n来回的最短路,不走重复路. 分析:可以考虑为1到n的流量为2时的最小花费: 建图: 一个点到一个点的容量为1,费用为距离. 1 #include <cstring> 2 #include <cstdio> 3 #include <vector> 4 #include <queue> 5 #include <algorit

Uva 1220,Hali-Bula 的晚会

题目链接:https://uva.onlinejudge.org/external/12/1220.pdf 题意: 公司n个人,形成一个数状结构,选出最大独立集,并且看是否是唯一解. 分析: d(i) 是 节点 i 的最优值, i 只有两种决策,就是选和不选. 转移方程: d(i) = max {1+Σ1d(j),Σ2d(j)}; Σ1是所有孙子节点,Σ2是所有儿子节点. 那么状态的定义d(i,0),节点 i 不选,d(i,1),节点 i 选. 那么状态转移方程就是: 是否唯一 f(v,0) =

Gopher II UVA 10080,最后被抓的地鼠有多少只?

. Gopher II UVA, 10080 Time Limit: 3000 MS The gopher family, having averted the canine threat, must face a new predator. The are n gophers and m gopher holes, each at distinct (x, y) coordinates. A hawk arrives and if a gopher does not reach a hole

Uva 116,单向TSP

题目链接:https://uva.onlinejudge.org/external/1/116.pdf 和矩形嵌套,巴比伦塔差不多. 题意: 给出矩阵,这个矩阵是环形的,就是说第一行的上一行是最后一行,最后一行的下一行是第一行,要求从最左边一列走到最右边一列,路径上的和最小.多组解输出字典序最小的解. 分析: DAG多段图,dp(i,j)从第i行,第j列出发的最优解,然后走一遍每一行的第一列. 这里的字典序最小,每次决策时的三个选择,每一行,重新排个序,这样就保证了字典序最小. 姜来是老的辣,写

uva 437,巴比伦塔

题目链接:https://uva.onlinejudge.org/external/4/437.pdf 题意:巴比伦塔: 给出n种立方体,一个立方体能放到另一个立方体上,必须满足,底面一定要小于下面的立方体.求巴比伦塔最多堆多高? 分析: DAG很容易想到,主要是状态的描叙. 一个立方体,他有3种情况,状态的描叙就用dp[id][3],此时dp[][i] I 来记录哪个是高. #include <bits/stdc++.h> using namespace std; int blocks[35

bzoj 1061 [Noi2008]志愿者招募(数学模型,MCMF)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1061 [题意] 雇人满足每天至少需要的人数. [思路一] Byvoid的题解 click here 任意一个变量在两个方程组中且一正一负,根据流量守恒的原理构图.正变量看作流入量,负变量看作流出量,正负常数看作与源汇点的流量. [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #includ