zoukankan      html  css  js  c++  java
  • hdu5249 Tricks Device(网络流最大匹配)

    分析题意可知:

    1、最少须要切断多少边使吴不能找到张(题意吴仅仅能走最短路径上面的边),对从起点到终点的最短路径又一次建图,每条边的权值为1。求最大流就可以

    2、在吴能够找到张的前提下,最多能够切断边的数量:仅仅须要在全部最短路径中寻找一条经过边数量最少的最短路径,用边的总数减去它就可以(逆向思维)

    代码例如以下:

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #define MAXN 2010
    #define INF 1e9+7
    using namespace std;
    struct Edge
    {
        int v,cost,cap;///v代表边的还有一个顶点。cost代表边的代价,cap代表反向边的位置
        Edge(int _v=0,int _cost=0,int _cap=0):v(_v),cost(_cost),cap(_cap) {}
    };
    vector<Edge> g[MAXN];///保存地图
    vector<int> pre[MAXN];///记录最短路径上每一个节点的父节点,用于构建网络流
    int flag[MAXN][MAXN];///解决重边问题
    int d[MAXN];///记录到达某一点的最短路径所经过的最短的边,用于求解问题2
    int dist[MAXN];
    struct qnode
    {
        int v;
        int c;
        qnode(int _v=0,int _c=0):v(_v),c(_c) {}
        bool operator<(const qnode &r)const
        {
            return c>r.c;
        }
    };
    int n,m;
    int level[MAXN];
    void Dijkstra(int s);
    void addedge(int u,int v,int w,int cap);
    void built(int u);
    int DINIC(int s,int t);
    int DFS(int now,int maxf,int t);
    bool makelevel(int s,int t);
    int main()
    {
       //FILE* fp = fopen("C:\Users\Crazy_Bear\Desktop\数据\data1007\1007.in","rw");
        while(scanf("%d%d",&n,&m)==2)
        {
            memset(g,0,sizeof(g));
            memset(flag,0,sizeof(flag));
            int x,y,v;
            for(int i=1; i<=m; ++i)
            {
                //fscanf(fp,"%d%d%d",&x,&y,&v);
                scanf("%d%d%d",&x,&y,&v);
                flag[x][y]++;///记录重边的数量
                addedge(x,y,v,0);
                flag[y][x]++;
                addedge(y,x,v,0);
            }
            Dijkstra(1);
            memset(g,0,sizeof(g));
            built(n);///又一次建图
            printf("%d %d
    ",DINIC(1,n),m-d[n]);
        }
       // fclose(fp);
        return 0;
    }
    void addedge(int u,int v,int w,int cap)
    {
        g[u].push_back(Edge(v,w,cap));
    }
    void Dijkstra(int s)
    {
        bool vis[MAXN];
        for(int i=1; i<=n; ++i)
        {
            vis[i]=false;
            dist[i]=INF;
            pre[i].clear();
            d[i]=INF;
        }
        priority_queue<qnode> pq;
        while(!pq.empty()) pq.pop();
        dist[s]=0;
        d[s]=0;
        pq.push(qnode(s,0));
        qnode tmp;
        while(!pq.empty())
        {
            tmp=pq.top();
            pq.pop();
            int u=tmp.v;
            if(vis[u]) continue;
            vis[u]=true;
            for(int i=0; i<g[u].size(); ++i)
            {
                int v=g[u][i].v;
                int cost=g[u][i].cost;
                if(dist[v]==dist[u]+cost)
                {
                    pre[v].push_back(u);///在求解最短路径的过程中记录父节点
                    d[v]=min(d[u]+1,d[v]);
                }
                else if(dist[v]>dist[u]+cost)
                {
                    dist[v]=dist[u]+cost;
                    pq.push(qnode(v,dist[v]));
                    d[v]=d[u]+1;
                    pre[v].clear();
                    pre[v].push_back(u);
                }
            }
        }
    }
    void built(int u)
    {
        if(u==1)
            return;
        int len=pre[u].size();
        for(int i=0; i<len; ++i)
        {
            if(flag[pre[u][i]][u]>0)
            {
                addedge(pre[u][i],u,1,g[u].size());
                flag[pre[u][i]][u]--;
                addedge(u,pre[u][i],1,g[pre[u][i]].size()-1);
                flag[u][pre[u][i]]--;
                built(pre[u][i]);
            }
        }
    }
    
    bool makelevel(int s,int t)
    {
        memset(level,0,sizeof(level));
        level[s]=1;
        int que[MAXN];
        int iq=0;
        que[iq++]=s;
        int top;
        for(int i=0; i<iq; ++i)
        {
            top=que[i];
            if(top==t) return true;
            int len=g[top].size();
            for(int i=0; i<len; ++i)
            {
                if(!level[g[top][i].v]&&g[top][i].cost)
                {
                    que[iq++]=g[top][i].v;
                    level[g[top][i].v]=level[top]+1;
                }
            }
        }
        return false;
    }
    int DFS(int now,int maxf,int t)
    {
    
        if(now==t) return maxf;
        int ret=0,f;
        int len=g[now].size();
        for(int i=0; i<len; ++i)
        {
            if(g[now][i].cost&&level[g[now][i].v]==level[now]+1)
            {
                f=DFS(g[now][i].v,min(maxf-ret,g[now][i].cost),t);
                g[now][i].cost-=f;
                g[g[now][i].v][g[now][i].cap].cost+=f;
                ret+=f;
                if(ret==maxf) return ret;
            }
        }
        return ret;
    }
    int DINIC(int s,int t)
    {
        int ans=0;
        while(makelevel(s,t)) ans+=DFS(s,INF,t);
        return ans;
    }
    


  • 相关阅读:
    第009题 智猜年龄——问经理三女儿年龄各多少
    第008题 求最大值——10个1加乘的最大数字
    第007题 天平称物——最少砝码称出最多质量
    第006题 天平找次——至少称几次找到次品
    第005题 青蛙过河——十只青蛙如何顺利过去
    第004题 过河问题——如何过河用时最短
    第003题 过河问题——三对老虎如何安全过河
    第002题 打水问题——9升和4L的桶如何打6升水
    基于博弈论分析在线教育网站和慕课的产生
    C++左右括号匹配问题(并给出括号的位置 并且允许非括号字符插入)修改版
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7145090.html
Copyright © 2011-2022 走看看