首页 > 搜索 > DFS搜索 > HDU 3435-A new Graph Game-网络流-[解题报告]HOJ
2014
03-23

HDU 3435-A new Graph Game-网络流-[解题报告]HOJ

A new Graph Game

问题描述 :

An undirected graph is a graph in which the nodes are connected by undirected arcs. An undirected arc is an edge that has no arrow. Both ends of an undirected arc are equivalent–there is no head or tail. Therefore, we represent an edge in an undirected graph as a set rather than an ordered pair.
Now given an undirected graph, you could delete any number of edges as you wish. Then you will get one or more connected sub graph from the original one (Any of them should have more than one vertex).
You goal is to make all the connected sub graphs exist the Hamiltonian circuit after the delete operation. What’s more, you want to know the minimum sum of all the weight of the edges on the “Hamiltonian circuit” of all the connected sub graphs (Only one “Hamiltonian circuit” will be calculated in one connected sub graph! That is to say if there exist more than one “Hamiltonian circuit” in one connected sub graph, you could only choose the one in which the sum of weight of these edges is minimum).
  For example, we may get two possible sums:
Sequence Adjustment

(1)  7 + 10 + 5 = 22
(2)  7 + 10 + 2 = 19
(There are two “Hamiltonian circuit” in this graph!)

输入:

In the first line there is an integer T, indicates the number of test cases. (T <= 20)
In each case, the first line contains two integers n and m, indicates the number of vertices and the number of edges. (1 <= n <=1000, 0 <= m <= 10000)
Then m lines, each line contains three integers a,b,c ,indicates that there is one edge between a and b, and the weight of it is c . (1 <= a,b <= n, a is not equal to b in any way, 1 <= c <= 10000)

输出:

In the first line there is an integer T, indicates the number of test cases. (T <= 20)
In each case, the first line contains two integers n and m, indicates the number of vertices and the number of edges. (1 <= n <=1000, 0 <= m <= 10000)
Then m lines, each line contains three integers a,b,c ,indicates that there is one edge between a and b, and the weight of it is c . (1 <= a,b <= n, a is not equal to b in any way, 1 <= c <= 10000)

样例输入:

3

3 4
1 2 5
2 1 2
2 3 10
3 1 7 

3 2
1 2 3
1 2 4

2 2
1 2 3
1 2 4

样例输出:

Case 1: 19
Case 2: NO
Case 3: 6
Hint
In Case 1: You could delete edge between 1 and 2 whose weight is 5. In Case 2: It’s impossible to get some connected sub graphs that any of them exists the Hamiltonian circuit after the delete operation.

将一个无向图删边得到一些子图,并使每个子图中存在哈密顿回路,并使所有哈密顿回路上边的权值最小。

因为是哈密顿图,所以每个点入度和出度必须为1,将每个点拆成u,u’,对于边<u,v>,连接边<u,v’>,<v,u’>,KM即可。

#include <stdio.h>
#include <string.h>
#define M 1100
#define inf 1000000

int nx,ny;
int link[M],lx[M],ly[M],slack[M];
int visx[M],visy[M],w[M][M];

int DFS(int x)
{
    visx[x] = 1;
    for (int y = 1;y <= ny;y ++)
    {
        if (visy[y])
            continue;
        int t = lx[x] + ly[y] - w[x][y];
        if (t == 0)       //
        {
            visy[y] = 1;
            if (link[y] == -1||DFS(link[y]))
            {
                link[y] = x;
                return 1;
            }
        }
        else if (slack[y] > t)
            slack[y] = t;
    }
    return 0;
}
long long  KM()
{
    int i,j;
    memset (link,-1,sizeof(link));
    memset (ly,0,sizeof(ly));
    for (i = 1;i <= nx;i ++)
        for (j = 1,lx[i] = -inf;j <= ny;j ++)
            if (w[i][j] > lx[i])
                lx[i] = w[i][j];

    for (int x = 1;x <= nx;x ++)
    {
        for (i = 1;i <= ny;i ++)
            slack[i] = inf;
        while (1)
        {
            memset (visx,0,sizeof(visx));
            memset (visy,0,sizeof(visy));
            if (DFS(x))
                break;

            int d = inf;
            for (i = 1;i <= ny;i ++)
                if (!visy[i]&&d > slack[i])
                    d = slack[i];
            for (i = 1;i <= nx;i ++)
                if (visx[i])
                    lx[i] -= d;
            for (i = 1;i <= ny;i ++)
                if (visy[i])
                    ly[i] += d;
                else
                    slack[i] -= d;
        }
    }
    long long  res = 0;
    for (i = 1;i <= ny;i ++)
    {
        if (link[i] == -1|| w[link[i]][i]==-inf)
            return 0;
        else res += w[link[i]][i];;
    }
    return res;
}

int main()
{
    int cas;
    int n,m;
    scanf("%d",&cas);
    int tot=0;
    while(cas--)
    {
        tot++;
        int i,j,x,y,z;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                w[i][j]=-inf;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            if(-z>w[x][y])
                w[x][y]=w[y][x]=-z;
        }
        nx=ny=n;
        long long ans=KM();
        if(ans==0)
            printf("Case %d: NO\n",tot);
        else
            printf("Case %d: %lld\n",tot,-ans);
    }
}

 

参考:http://blog.csdn.net/kidgin7439/article/details/21297963


  1. 给你一组数据吧:29 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 1000。此时的数据量还是很小的,耗时却不短。这种方法确实可以,当然或许还有其他的优化方案,但是优化只能针对某些数据,不太可能在所有情况下都能在可接受的时间内求解出答案。