HDU2448 Mining Station on the Sea Floyd算法+KM算法

Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=2448

 

【题意】

 

给定m个station的无向连接图,

再给定m个station上任意的n个vessel(n<=m),

再给定n个port,同时给出station到port的有向连接图,

要求n个vessel回到n个port的最小权值和。

一个port只能容纳一个vessel。

vessel可以在station之间行走。

 

【思路】

 

粗略地读了一遍题,没怎么读懂,后来读了一遍,想到了这个思路。

对station进行Floyd算法的运算,求出所有station之间的最短路径。

根据vessel和port建立二分图。左右均为n个端点。

对于每一条station到port的边,枚举每一个vessel,若vessel经过这个station再到达port的路径和小于其原始值(vessel到port),则更新这个值。

这样,插入所有边之后就建立好了二分图。

再运用KM算法,求出最小权值和。

 

【P.S】

 

DEBUG之后1A。

发现是2008 Asia Regional Harbin。

 

【代码】

 

#include <iostream>
using namespace std;
#define min(a,b) ((a)<=(b)?(a):(b))

const int maxn = 100;//二分图左端点个数
const int maxm = 100;//二分图右端点个数
const int inf = (1<<30);//定义最大值
  
int w[maxn+5][maxm+5]; //权值邻接矩阵,初始化为-inf,之后填入权值。
int lx[maxn+5], ly[maxm+5]; 
int linky[maxm+5];//存储右端点对应的左端点匹配,-1表示无匹配
bool visx[maxn+5], visy[maxm+5];  
int lack;
  
  
bool find(int v, int m)  
{  
    int i, t;  
    visx[v] = true;  
    for (i=1; i<=m; i++)  
    {  
        if (w[v][i]==-inf || visy[i]) continue;
        t = lx[v] + ly[i] - w[v][i];  
        if (t==0)  
        {  
            visy[i] = true;  
            if (linky[i]==-1 || find(linky[i], m))  
            {  
                linky[i] = v;  
                return true;  
            }  
        }  
        else lack = min(lack, t);  
    }  
    return false;  
}  
  
int KM(int n, int m)
{  
    int i, j;  
    for (i=0; i<=m; i++)  
    {  
        ly[i] = 0;  
        linky[i] = -1;  
    }  
    for (i=1; i<=n; i++)  
    {  
        lx[i] =-inf;  
        for (j=1; j<=m; j++)  
        {  
            if (w[i][j]>lx[i])  
                lx[i] = w[i][j];  
        }  
    }  
    for (i=1; i<=n; i++)  
    {  
        while(true)  
        {  
            for (j=0; j<=n; j++) visx[j] = false;  
            for (j=0; j<=m; j++) visy[j] = false;  
            lack = inf;  
            if (find(i, m)) break;  
            for (j=1; j<=n; j++) 
            {  
                if (visx[j]) lx[j] -= lack;  
            }  
            for (j=1; j<=m; j++)  
            {  
                if (visy[j]) ly[j] += lack;  
            }  
        }  
    }  
    int ans = 0;  
    for (i=1; i<=m; i++)  
    {  
        if (linky[i]>-1)  
        {  
            ans += w[linky[i]][i]; 
        }  
    }  
    return -ans;
}

int station[205][205];
int vessel[maxn+5];

void Floyd(int n)
{
	int i, j, k;
	for (k=1; k<=n; k++)
	{
		for (i=1; i<=n; i++)
		{
			if (station[i][k]>=inf) continue;
			for (j=1; j<=n; j++)
			{
				if (station[k][j]>=inf) continue;
				station[i][j] = min(station[i][j], station[i][k]+station[k][j]);
			}
		}
	}
}

int main()
{
	int n, m, k, p;
	int a, b, c;
	int i, j;
	while(scanf("%d %d %d %d", &n, &m, &k, &p)!=EOF)
	{
		for (i=1; i<=n; i++)
		{
			scanf("%d", &vessel[i]);
		}
		for (i=1; i<=m; i++)//初始化station
		{
			station[i][i] = 0;
			for (j=1; j<i; j++)
			{
				station[i][j] = station[j][i] = inf;
			}
		}
		for (i=0; i<k; i++)//建立station
		{
			scanf("%d %d %d", &a, &b, &c);
			station[a][b] = station[b][a] = min(station[a][b], c);
		}
		Floyd(m);//Floyd运算
		for (i=1; i<=n; i++)//初始化KM权值矩阵
		{
			for (j=1; j<=n; j++)
			{
				w[i][j] = inf;
			}
		}
		for (i=0; i<p; i++)//建立矩阵
		{
			scanf("%d %d %d", &b, &a, &c);
			for (j=1; j<=n; j++)
			{
				w[j][b] = min(w[j][b], station[vessel[j]][a]+c);
			}
		}
		for (i=1; i<=n; i++)//求最小权值时应取其相反数
		{
			for (j=1; j<=n; j++)
			{
				w[i][j] *= (-1);
			}
		}
		printf("%d\n", KM(n, n));//KM算法运算
	}
	return 0;
}


 

你可能感兴趣的:(c,算法,存储)