hdu 2448(KM算法+SPFA)

Mining Station on the Sea

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2997    Accepted Submission(s): 913

Problem Description

The
ocean is a treasure house of resources and the development of human
society comes to depend more and more on it. In order to develop and
utilize marine resources, it is necessary to build mining stations on
the sea. However, due to seabed mineral resources, the radio signal in
the sea is often so weak that not all the mining stations can carry out
direct communication. However communication is indispensable, every two
mining stations must be able to communicate with each other (either
directly or through other one or more mining stations). To meet the need
of transporting the exploited resources up to the land to get put into
use, there build n ports correspondently along the coast and every port
can communicate with one or more mining stations directly.

Due to
the fact that some mining stations can not communicate with each other
directly, for the safety of the navigation for ships, ships are only
allowed to sail between mining stations which can communicate with each
other directly.

The mining is arduous and people do this job
need proper rest (that is, to allow the ship to return to the port). But
what a coincidence! This time, n vessels for mining take their turns to
take a rest at the same time. They are scattered in different stations
and now they have to go back to the port, in addition, a port can only
accommodate one vessel. Now all the vessels will start to return, how to
choose their navigation routes to make the total sum of their sailing
routes minimal.

Notice that once the ship entered the port, it will not come out!

Input

There
are several test cases. Every test case begins with four integers in
one line, n (1 = <n <= 100), m (n <= m <= 200), k and p. n
indicates n vessels and n ports, m indicates m mining stations, k
indicates k edges, each edge corresponding to the link between a mining
station and another one, p indicates p edges, each edge indicating the
link between a port and a mining station. The following line is n
integers, each one indicating one station that one vessel belongs to.
Then there follows k lines, each line including 3 integers a, b and c,
indicating the fact that there exists direct communication between
mining stations a and b and the distance between them is c. Finally,
there follows another p lines, each line including 3 integers d, e and
f, indicating the fact that there exists direct communication between
port d and mining station e and the distance between them is f. In
addition, mining stations are represented by numbers from 1 to m, and
ports 1 to n. Input is terminated by end of file.

Output

Each test case outputs the minimal total sum of their sailing routes.

Sample Input

3 5 5 6
1 2 4
1 3 3
1 4 4
1 5 5
2 5 3
2 4 3
1 1 5
1 5 3
2 5 3
2 4 6
3 1 4
3 2 2

Sample Output

13

题意:现在有m个油井和n个港口(n<=m),现在有n条船停在这些油井这里,第一行输入n个数, 输入IDX[i]代表第i条船停在 IDX[i]这个油井这里,然后接下来有k行,输入u,v,w代表油井u和油井v之间的距离为w,然后又p行,代表了港口和油井之间的距离,现在这些船全部要回到港口,而且每个港口只能停一艘船,问这些船返回港口的最短距离。

题解:开始的时候建边,要为油田和油田建双向边,但是油田港口只能建单向边,因为回去了就不能往回走了.用spfa求出每艘船到每个港口的距离(注意编号,港口编号为 1+m~n+m),然后求出来之后进行KM算法最优匹配即可得到答案。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <stdlib.h>
using namespace std;
const int N = 400;
const int INF = 999999999;
int lx[N],ly[N];
bool visitx[N],visity[N];
int slack[N];
int match[N];
int graph[N][N];
int idx[N]; ///船所在的油井下标
int n,m,k,p;
bool Hungary(int u)
{
    visitx[u] = true;
    for(int i=m+1; i<=m+n; i++)
    {
        if(!visity[i])
        {
            int temp = lx[u]+ly[i]-graph[u][i];
            if(temp==0)
            {
                visity[i] = true;
                if(match[i]==-1||Hungary(match[i]))
                {
                    match[i] = u;
                    return true;
                }
            }
            else
            {
                slack[i] = min(slack[i],temp);
            }
        }
    }
    return false;
}
void KM()
{
    memset(match,-1,sizeof(match));
    memset(ly,0,sizeof(ly));
    for(int i=1; i<=n; i++) ///定标初始化
    {
        lx[idx[i]] = -INF;
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=m+1; j<=n+m; j++)
        {
            lx[idx[i]] = max(lx[idx[i]],graph[idx[i]][j]);
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=m+1; j<=m+n; j++) slack[j] = INF;
        while(true)
        {
            memset(visitx,false,sizeof(visitx));
            memset(visity,false,sizeof(visity));
            if(Hungary(idx[i])) break;
            else
            {
                int temp = INF;
                for(int j=1+m; j<=n+m; j++)
                {
                    if(!visity[j]) temp = min(temp,slack[j]);
                }
                for(int j=1; j<=n; j++)
                {
                    if(visitx[idx[j]]) lx[idx[j]]-=temp;
                }
                for(int j=1; j<=n+m; j++)
                {
                    if(visity[j]) ly[j]+=temp;
                    else slack[j]-=temp;
                }
            }
        }
    }
}
struct Edge
{
    int v,w,next;
} edge[N*N];
int head[N],tot;
void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}
void addEdge(int u,int v,int w,int &k)
{
    edge[k].v = v,edge[k].w = w,edge[k].next = head[u],head[u] = k++;
}
int low[N];
bool vis[N];
void spfa(int s)
{
    for(int i=1; i<=n+m; i++)
    {
        low[i] = INF;
        vis[i] = false;
    }
    queue<int> q;
    low[s] = 0;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v = edge[i].v,w = edge[i].w;
            if(low[v]>low[u]+w)
            {
                low[v] = low[u]+w;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    for(int i=1+m; i<=n+m; i++)
    {
        if(low[i]!=INF)
        {
            graph[s][i] = -low[i];
        }
    }
}
int main()
{
    while(scanf("%d%d%d%d",&n,&m,&k,&p)!=EOF)
    {
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&idx[i]);
        }
        /**油田 1-m,港口 m+1-m+n*/
        for(int i=1; i<=k; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addEdge(u,v,w,tot);
            addEdge(v,u,w,tot);
        }
        for(int i=1; i<=p; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addEdge(v,u+m,w,tot); ///油井向港口添加单向边
        }
        memset(graph,0,sizeof(graph));
        for(int i=1; i<=n; i++)
        {
            spfa(idx[i]);
        }
        KM();
        int ans = 0;
        for(int i=1+m; i<=n+m; i++)
        {
            if(match[i]!=-1)
            {
                ans+=graph[match[i]][i];
            }
        }
        printf("%d\n",-ans);
    }
}
时间: 2024-10-13 12:22:55

hdu 2448(KM算法+SPFA)的相关文章

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

hdu 3488(KM算法||最小费用最大流)

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 2925    Accepted Submission(s): 1407 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000

HDU 1533 KM算法(权值最小的最佳匹配)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3299    Accepted Submission(s): 1674 Problem Description On a grid map there are n little men and n houses. In each unit time, every l

hdu 2255(KM算法模板)

奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3707    Accepted Submission(s): 1618 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考

Mining Station on the Sea (hdu 2448 SPFA+KM)

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2584    Accepted Submission(s): 780 Problem Description The ocean is a treasure house of resources and the development

HDU 2255 奔小康赚大钱(二分匹配之KM算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子. 另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓

hdu 2255 奔小康赚大钱(KM算法)

奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3248    Accepted Submission(s): 1413 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考

hdu 1533 Going Home (KM算法)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2715    Accepted Submission(s): 1366 Problem Description On a grid map there are n little men and n houses. In each unit time, every

hdu 1853 Cyclic Tour &amp;&amp; hdu 3435 A new Graph Game(简单KM算法)

Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1478    Accepted Submission(s): 750 Problem Description There are N cities in our country, and M one-way roads connecting them. Now L