• SGU 206 Roads


    SGU_206

        不得不说这个题目的思想太奇葩,一时间还是不能很理解……

        首先一个贪心的思路就是,石子路的d[i]一定是小于或等于c[i]的,而非石子路的d[j]是一定大于或等于c[j]的,如果我们用x[i]描述石子路谎报的增量那么有x[i]=c[i]-d[i],用y[j]描述非石子路谎报的增量那么有y[j]=d[j]-c[j],最后目标自然就是求sum{x[i]}+sum{y[j]}的最小值了。

        接着考虑题目中给出的重要条件,即最后要让石子路形成最小生成树,那么对于任意一条非石子路,填加到最小生成树上就会形成一个环,如果这条非石子路d[j]比环上某条石子路的d[i]小的话,那么这条非石子路就可以替换掉那条石子路成为最小生成树上的边,这样就与假设的“石子路形成最小生成树”相矛盾了,因此,对于环上的任意一条石子路都有d[j]>=d[i]。

        现在条件都已经分析完了,乍看起来是个很头疼的问题,因为我们要根据推出的这些不等式来确定sum{x[i]}+sum{y[j]}的最小值,这样就可能要用到线性规划这个的东西了,至少现在我还不会线性规划……但如果将原来的不等式加以变形的话,很奇葩地就能KM挂上钩了……

        由d[j]>=d[i],我们可以得到y[j]+c[j]>=c[i]-x[i],将变量x[i]、x[j]移到一边去就得到了x[i]+y[j]>=c[i]-c[j],而这个式子和KM中的A[i]+B[j]>=G[i][j]是很像的。再联想到KM求解的过程,实际上就是在满足所有A[i]+B[j]>=G[i][j]的前提条件下,不断缩小A[i],当缩到不能缩时,也就是当出现A[i]+B[j]==G[i][j]的时候,就会完成一条匹配,于是做完KM之后实际上就保证了sum{A[i]}+sum{B[j]}的值最小了。

        这样这个题目的思路就有了,找到所有的d[j]>=d[i]的关系并转化成x[i]+y[j]>=c[i]-c[j]这样的关系,然后连一条i到j的权值为c[i]-c[j]边,如果两边点数不一样的话就补点使两边的点数相等,然后将边补全,补的边的权值都看作0,最后做完KM之后根据A[i]、B[j]的值就可以计算出d[i]、d[j]的值了。在建图的时候,如果c[i]-c[j]<0,可以直接将这条边看成0,因为增量都是正的,所以有一个隐含条件x[i]+y[j]>=0。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXN 70
    #define MAXD 410
    #define MAXM 810
    #define INF 0x3f3f3f3f
    int N, M, D, first[MAXN], e, next[MAXM], v[MAXM], w[MAXM], c[MAXM];
    int g[MAXD][MAXD], visx[MAXD], visy[MAXD], A[MAXD], B[MAXD], slack, yM[MAXD];
    void add(int x, int y, int z)
    {
        v[e] = y, w[e] = z;
        next[e] = first[x], first[x] = e ++;    
    }
    int dfs(int cur, int fa, int t, int id, int value)
    {
        int i;
        if(cur == t) return 1;
        for(i = first[cur]; i != -1; i = next[i])
            if(v[i] != fa && dfs(v[i], cur, t, id, value))
            {
                g[i / 2][id] = std::max(g[i / 2][id], w[i] - value);
                return 1;
            }
        return 0;
    }
    void init()
    {
        int i, x, y, z;
        N -= 1;
        memset(first, -1, sizeof(first)), e = 0;
        for(i = 0; i < N; i ++)
        {
            scanf("%d%d%d", &x, &y, &z);
            add(x, y, z), add(y, x, z);
        }
        memset(g, 0, sizeof(g));
        M -= N;
        for(i = 0; i < M; i ++)
        {
            scanf("%d%d%d", &x, &y, &z), c[i] = z;
            dfs(x, -1, y, i, z);    
        }
    }
    int searchpath(int cur, int n)
    {
        int i;
        visx[cur] = 1;
        for(i = 0; i < n; i ++)
            if(!visy[i])
            {
                int t = A[cur] + B[i] - g[cur][i];
                if(t == 0)
                {
                    visy[i] = 1;
                    if(yM[i] == -1 || searchpath(yM[i], n))
                    {
                        yM[i] = cur;
                        return 1;
                    }
                }
                else
                    slack = std::min(slack, t);
            }
        return 0;
    }
    void solve()
    {
        int i, j, n = std::max(N, M);
        memset(B, 0, sizeof(B[0]) * n);
        for(i = 0; i < n; i ++)
            for(j = A[i] = 0; j < n; j ++) A[i] = std::max(A[i], g[i][j]);
        memset(yM, -1, sizeof(yM[0]) * n);
        for(i = 0; i < n; i ++)
            for(;;)
            {
                slack = INF;
                memset(visx, 0, sizeof(visx[0]) * n);
                memset(visy, 0, sizeof(visy[0]) * n);
                if(searchpath(i, n)) break;
                for(j = 0; j < n; j ++) if(visx[j]) A[j] -= slack;
                for(j = 0; j < n; j ++) if(visy[j]) B[j] += slack;
            }
        for(i = 0; i < N; i ++)
            printf("%d\n",  - A[i] + w[i << 1]);
        for(i = 0; i < M; i ++)
            printf("%d\n", B[i] + c[i]);
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) == 2)
        {
            init();
            solve();    
        }
        return 0;    
    }
  • 相关阅读:
    sprintf使用
    Android ListView保持选中项高亮
    Creational Patterns创建型模式
    C和指针终于看到指针这一章
    C++随笔001
    TCP reset
    开始看设计模式英文版了
    Excel条件求和
    linux中安装软件,查看、卸载已安装软件方法
    linux vi文本编辑器三种模式切换及常用操作
  • 原文地址:https://www.cnblogs.com/staginner/p/2646472.html
Copyright © 2020-2023  润新知