zoukankan      html  css  js  c++  java
  • 《浅谈图论模型的建立与应用》

    图论的建模,就是要抓住问题的本质,把问题抽象为点、边、权的关系。

    Place the Robots (ZOJ 1654)

    • 方案一:只关心空地与空地之间的联系,发生冲突的节点,连一条边,转换为求最大独立集。时间复杂度为:n*2^n

    • 方案二:将所有横向方块,纵向方块分成X,Y部分,每个方块只能放一个机器人,那么有冲突的方块连一条边,问题转换为求最大匹配,最大匹配=最大流。

    Source Code:

    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    const int maxn = 1250;
    const int INF = 0x3f3f3f3f;
    
    int n,m;
    char maps[maxn][maxn];
    
    int col[maxn][maxn],row[maxn][maxn];
    
    int head[maxn*maxn];
    
    struct Edge
    {
        int to;
        int next;
    } edges[maxn];
    
    int cnt;
    
    void add(int u,int v)
    {
        edges[cnt].to = v;
        edges[cnt].next = head[u];
        head[u] = cnt++;
    }
    
    bool vis[maxn];
    int match[maxn];
    bool dfs(int u) {
        for(int i=head[u];~i;i=edges[i].next) {
            int v = edges[i].to;
            if(!vis[v]) {
                vis[v] = 1;
                if(match[v]==-1||dfs(match[v])) {
                    match[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int R,C;
    int solve() {
        int num = 0;
    
        memset(match,-1,sizeof(match));
        for(int i=0;i<R;i++) {
            memset(vis,0,sizeof(vis));
            if(dfs(i))
                num++;
        }
        return num;
    }
    
    
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        int t;
        scanf("%d",&t);
        for(int z=0; z<t; z++)
        {
            cnt = 0;
            scanf("%d%d",&n,&m);
            for(int i=0; i<n; i++)
                scanf("%s",maps[i]);
    
            R= 0,C=0;
            memset(col,0,sizeof(col));
            memset(row,0,sizeof(row));
            memset(head,-1,sizeof(head));
    
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<m; j++)
                {
                    if(maps[i][j]=='o')
                    {
                        int tmp = j;
                        while(tmp>=0)
                        {
                            if(maps[i][tmp]!='#')
                            {
                                row[i][tmp] = R;
                                tmp--;
                            }
                            else break;
                        }
                        while(j<m)
                        {
                            if(maps[i][j]!='#')
                            {
                                row[i][j] = R;
                                j++;
                            }
                            else break;
                        }
                        R++;
                    }
                }
            }
    
            for(int j=0; j<m; j++)
            {
                for(int i=0; i<n; i++)
                {
                    if(maps[i][j]=='o')
                    {
                        int tmp = i;
                        while(tmp>=0)
                        {
                            if(maps[tmp][j]!='#')
                            {
                                col[tmp][j] = C;
                                tmp--;
                            }
                            else break;
                        }
                        while(i<n)
                        {
                            if(maps[i][j]!='#')
                            {
                                col[i][j] = C;
                                i++;
                            }
                            else break;
                        }
                        C++;
                    }
                }
            }
    
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++)
                    if(maps[i][j]=='o')
                        add(row[i][j],col[i][j]);
    
    
            printf("Case :%d
    %d
    ",z+1,solve());
    
        }
        return 0;
    }
    

    差分约束:

    x_1-x_2<=b_1

    x_2-x_3<=b_2

    x_3-x_4<=b_3

    x_4-x_5<=b_4

    o x_1-x_5<=4 ag{1}

    如果存在负环:

    x_5-x_1<=-5 ag{2}

    (1)(2)相加

    0<=-1 ag{3}

    无解,在图上表示,及存在负环。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 30;
    
    int r[maxn];
    int t[maxn];
    
    struct Edge {
        int from,to,dist;
    };
    
    struct BellmanFord {
        int n,m;
        vector<Edge> edges;
        vector<int> G[maxn];
        bool inq[maxn];
        int d[maxn];
        int p[maxn];
        int cnt[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 dist) {
            edges.push_back((Edge){from,to,dist});
            m = edges.size();
            G[from].push_back(m-1);
        }
    
        bool negativeCycle() {
            queue<int> Q;
            memset(inq,0,sizeof(inq));
            memset(cnt,0,sizeof(cnt));
    
            for(int i=0;i<n;i++) {
                d[i] = 0;
                inq[0] = true;
                Q.push(i);
            }
    
            while(!Q.empty()) {
                int u = Q.front();Q.pop();
                inq[u] = false;
                for(int i=0;i<G[u].size();i++) {
                    Edge& e = edges[G[u][i]];
                    if(d[e.to]>d[u]+e.dist) {
                        d[e.to] = d[u] + e.dist;
                        p[e.to] = G[u][i];
                        if(!inq[e.to]) {
                            Q.push(e.to);
                            inq[e.to] = true;
                            if(++cnt[e.to]>n)
                                return true;
                        }
                    }
                }
            }
    
            return false;
        }
    
    }sol;
    
    
    void build(int ans) {   
    
        sol.init(25);
    
        for(int i=1;i<=24;i++) {
            sol.addEdge(i-1,i,t[i]);
            sol.addEdge(i,i-1,0);
        }
    
        for(int i=8;i<=24;i++)
            sol.addEdge(i,i-8,-r[i]);
    
        for(int i=1;i<8;i++)
            sol.addEdge(i,24+i-8,ans-r[i]);
    
        sol.addEdge(24,0,-ans);
    
    }
    
    int main()
    {
        freopen("in.txt","r",stdin);
        int tt;
        scanf("%d",&tt);
        for(int z=0;z<tt;z++) {
    
            bool flag = false;;
            for (int i = 1; i <= 24; ++ i)
                scanf("%d", &r[i]);
    
            scanf("%d", &n);
            memset(t,0,sizeof(t));
            int x;
            for(int i=0;i<n;i++) {
                scanf("%d",&x);
                x++;
                t[x]++;
            }
    
            int l= 0,r=n;
            int ans = -1;
            while(l<=r) {
                int mid = (l+r)>>1;
                build(mid);
                if(sol.negativeCycle()) {
                    ans = mid;
                    r = mid-1;
                }
                else l = mid+1;
            }
    
            printf("%d
    ",ans);
    
        }
        return 0;
    }
    

    本题的卡片总数有十万之多,而最终要选取的卡片数不超过100张。如果在构图之前,把没有用的卡片先删掉,必将大大提高效率。
    什么样的卡片是没有用的呢?
    先考虑第一种能力的选取:如果把全部卡片按第一种能力值从大到小排序,显然我们应该尽量从前面选A张出来,由于每张卡片只能使用一次,所以有可能会和其他的两种能力发生冲突,而冲突的卡片数最多是B+C张,所以实际上对我们有用的卡片只是前面的A+B+C张。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 500, INF = 1000000000;
    
    struct Edge
    {
        int from, to, cap, flow, cost;
    };
    
    struct MCMF
    {
        int n, m;
        vector<Edge> edges;
        vector<int> G[maxn];
        bool 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();
            edges.clear();
        }
    
        void AddEdge(int from, int to, int cap, int cost)
        {
            edges.push_back((Edge)
            {
                from, to, cap, 0, cost
            });
            edges.push_back((Edge)
            {
                to, from, 0, 0, -cost
            });
            m = edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BellmanFord(int s, int t, int &flow, long long& cost)
        {
            memset(inq,0,sizeof(inq));
            for(int i=0; i<n; i++)
                d[i] = INF;
            d[s] = 0;
            inq[s] = true;
            p[s] = 0;
            a[s] = INF;
    
            queue<int> Q;
            Q.push(s);
            while(!Q.empty())
            {
                int u = Q.front();
                Q.pop();
                inq[u] = false;
                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] = true;
                        }
                    }
                }
            }
            if(d[t] == INF) return false; //s-t 不连通,失败退出
            flow += a[t];
            cost += (long long)d[t] * (long long)a[t];
            int u = t;
            while(u != s)
            {
                edges[p[u]].flow += a[t];
                edges[p[u]^1].flow -= a[t];
                u = edges[p[u]].from;
            }
            return true;
        }
    
        pair<long long,int>Mincost(int s, int t)
        {
            long long cost = 0;
            int flow = 0;
            while(BellmanFord(s, t, flow, cost));
            return pair<long long,int> {cost,flow};
        }
    } sol;
    
    
    int a[100105],b[100105],c[100105],rk[100105];
    int id[310];
    bool cmpa(int i,int j)
    {
        if(a[i]==a[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j];
        return a[i]>a[j];
    }
    bool cmpb(int i,int j)
    {
        if(b[i]==b[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j];
        return b[i]>b[j];
    }
    bool cmpc(int i,int j)
    {
        if(c[i]==c[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j];
        return c[i]>c[j];
    }
    
    int main()
    {
       // freopen("in.txt","r",stdin);
        int t;
        scanf("%d",&t);
        for(int i=0; i<t; i++)
        {
            int n;
            scanf("%d",&n);
            int A,B,C;
            scanf("%d%d%d",&A,&B,&C);
            for(int i=1; i<=n; i++)
                scanf("%d%d%d",&a[i],&b[i],&c[i]);
    
            for(int i=1; i<=n; i++)rk[i]=i;
            sort(rk+1,rk+1+n,cmpa);
            for(int i=1; i<=A+B+C; i++)id[i]=rk[i];
    
            for(int i=1; i<=n; i++)rk[i]=i;
            sort(rk+1,rk+1+n,cmpb);
            for(int i=1; i<=A+B+C; i++)id[i+A+B+C]=rk[i];
    
            for(int i=1; i<=n; i++)rk[i]=i;
            sort(rk+1,rk+1+n,cmpc);
            for(int i=1; i<=A+B+C; i++)id[i+2*(A+B+C)]=rk[i];
    
            int m=3*(A+B+C);
            sort(id+1,id+1+m);
            m=unique(id+1,id+1+m)-id-1;
    
            sol.init(m+5);
            int s = 0;
            int p1 = m+1;
            int p2 = m+2;
            int p3 = m+3;
            int t = m+4;
    
            sol.AddEdge(s,p1,A,0);
            sol.AddEdge(s,p2,B,0);
            sol.AddEdge(s,p3,C,0);
    
            for(int i=1; i<=m; i++)
            {
                sol.AddEdge(p1,i,1,-a[id[i]]);
                sol.AddEdge(p2,i,1,-b[id[i]]);
                sol.AddEdge(p3,i,1,-c[id[i]]);
            }
    
            for(int i=1;i<=m;i++)
                sol.AddEdge(i,t,1,0);
    
    
            printf("%I64d ",-sol.Mincost(s,t).first);
    
            int k = 6*m+7;
            long long ans2 = 0;
            for(int i=1; i<=m; i++)
            {
                if(sol.edges[k].flow!=0)
                {
                    ans2 += (a[id[i]]+b[id[i]]+c[id[i]]);
                }
                k+=2;
            }
            printf("%I64d
    ",ans2);
    
        }
        return 0;
    }
  • 相关阅读:
    spoj1812 Longest Common Substring II( 后缀自动机 )
    SPOJ8222 Substrings( 后缀自动机 + dp )
    BZOJ 2882: 工艺( 后缀自动机 )
    NOIP2015酱油记
    NOIP2015前
    BZOJ 1088: [SCOI2005]扫雷Mine( )
    BZOJ 1261: [SCOI2006]zh_tree( 区间dp )
    HDU4027 Can you answer these queries? 线段树
    ZOJ3261 Connections in Galaxy War 并查集
    POJ 1773 Parity game 带权并查集
  • 原文地址:https://www.cnblogs.com/TreeDream/p/7323683.html
Copyright © 2011-2022 走看看