HDU ACM 4494 Teamwork 最小费用最大流

题意:n个工作地,m种工人,工作地0是仓库,其他的都需要修缮,每个地点需要多个工种的工人若干,不同工种不能相互取代。每个工作地有一个开工时间,凑齐所有工人后准时开工,修缮也需要一定时间。一个工人可以在一个地方工作完后再到其他地方,两地直接的距离是欧几里得距离,可以算作时间。最少需要多少工人。

分析:只用费用流。每种工人不能相互替换,没有任何关系。因此对每个工种进行建图求解最小费用累加即可得到最终结果。

超级源点cs是仓库,超级汇点为ct。

一个地点拆成三个点,i、i’、i”。k表示工种,对每个点建边。

S -> i : 容量为v[i][k],费用为1.

i -> i’ : 容量为v[i][k],费用为0.

i’ -> T : 容量为v[i][k],费用为0.S -> i” : 容量为v[i][k],费用为0.

如果工人可以在地点i工作完成后到达地点j开工,建边i” -> j’ : 容量为v[i][k],费用为0.这样建边相当于j点的流量减小了v[i][k]。

#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;  

#define N 500
#define inf 0x3f3f3f3f
#define min(a,b) ((a)<(b)?(a):(b))

class MCMF            //最小费用最大流
{
private:
    struct EDGE
    {
        EDGE(int _from,int _to,int _cap,int _flow,int _cost)
        {
            from=_from;
            to=_to;
            cap=_cap;
            flow=_flow;
			cost=_cost;
        }
        int from,to,cap,flow,cost;
    };  

public:
    MCMF(){ m_iM=0;}
    ~MCMF(){}
    void AddEdge(int _from,int _to,int _cap,int _cost);  //_cap表示容量
    int MinCost(int s,int t);
	void Init(int n);

private:
	bool BellmanFord(int s,int t,int& flow,int& cost);  //沿最短路增广

    int m_iN,m_iM,m_iS,m_iT;   //节点数,边数(包括反向边),源点,汇点
    vector<EDGE> m_vEdges;        //边表m_edges[e]和m_edges[e^1]互为反向弧
    vector<int> m_vG[N];            //领接表
	int m_iD[N];                  //Bellman-Ford
	int m_iP[N];                  //上一条弧
	int m_iA[N];                  //可改进量
	bool m_bInq[N];               //是否在队列中
};

int MCMF::MinCost(int s,int t)
{
	int flow=0,cost=0;

	while(BellmanFord(s,t,flow,cost)) ;  //求出最小费用最大流
	return cost;
}

void MCMF::Init(int n)
{
	int i;

	for(i=0;i<n;i++) m_vG[i].clear();
	m_vEdges.clear();
	m_iM=0;
	m_iN=n;
}

void MCMF::AddEdge(int _from,int _to,int _cap,int _cost)
{
    m_vEdges.push_back(EDGE(_from,_to,_cap,0,_cost));
    m_vEdges.push_back(EDGE(_to,_from,0,0,-_cost));
    m_iM+=2;
    m_vG[_from].push_back(m_iM-2);
    m_vG[_to].push_back(m_iM-1);
}

bool MCMF::BellmanFord(int s,int t,int& flow,int& cost)
{
	int i,u;

	for(i=0;i<m_iN;i++) m_iD[i]=inf;
	memset(m_bInq,false,sizeof(m_bInq));
	m_iD[s]=0;
	m_bInq[s]=1;
	m_iP[s]=0;
	m_iA[s]=inf;

	queue<int> q;
	q.push(s);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		m_bInq[u]=false;
		for(i=0;i<m_vG[u].size();i++)
		{
			EDGE& e=m_vEdges[m_vG[u][i]];
			if(e.cap>e.flow && m_iD[e.to]>m_iD[u]+e.cost)
			{
				m_iD[e.to]=m_iD[u]+e.cost;
				m_iP[e.to]=m_vG[u][i];
				m_iA[e.to]=min(m_iA[u],e.cap-e.flow);

				if(!m_bInq[e.to])
				{
					q.push(e.to);
					m_bInq[e.to]=true;
				}
			}
		}
	}
	if(m_iD[t]==inf) return false;      //s-t不连通,找不到增广路
	flow+=m_iA[t];
	cost+=m_iD[t]*m_iA[t];

	u=t;
	while(u!=s)
	{
		m_vEdges[m_iP[u]].flow+=m_iA[t];
		m_vEdges[m_iP[u]^1].flow-=m_iA[t];
		u=m_vEdges[m_iP[u]].from;
	}
	return true;
}

struct Node         //地点
{
	int st,cost,v[10];           //v[10]表示需要工人种类的数目
	double x,y;
} node[N];

bool map[N][N];              //判断是否可以在一个点完成后到另一个点

int main()
{
	int T,n,m,i,j,ans,k,cs,ct;
	MCMF mcmf;

	ios::sync_with_stdio(false);
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		cin>>node[0].x>>node[0].y;  //工厂的地点
		for(i=1;i<n;i++)
		{
			cin>>node[i].x>>node[i].y>>node[i].st>>node[i].cost;
			for(j=0;j<m;j++)
				cin>>node[i].v[j];
		}
		memset(map,false,sizeof(map));
		for(i=1;i<n;i++)
			for(j=1;j<n;j++)
				if(i!=j && node[i].st+node[i].cost+sqrt(pow(node[i].x-node[j].x,2.0)+
					pow(node[i].y-node[j].y,2.0))<=node[j].st)
					map[i][j]=1;

		ans=0;
		for(k=0;k<m;k++)       //对于每种工人进行一次最小费用最大流
		{
			cs=0;         //超级源点
			ct=3*n+1;    //超级汇点
			mcmf.Init(3*n+10);
			for(i=1;i<n;i++)
			{
				mcmf.AddEdge(cs,i,node[i].v[k],1);
				mcmf.AddEdge(i,i+n,node[i].v[k],0);
				mcmf.AddEdge(cs,i+n*2,node[i].v[k],0);
				mcmf.AddEdge(i+n,ct,node[i].v[k],0);
				for(j=1;j<n;j++)
					if(map[i][j])
						mcmf.AddEdge(i+n*2,j+n,node[i].v[k],0);
			}
			ans+=mcmf.MinCost(cs,ct);   //求出每种工人的最小费用并相加
		}
		cout<<ans<<endl;
	}
    return 0;
}
时间: 2024-08-27 15:57:23

HDU ACM 4494 Teamwork 最小费用最大流的相关文章

hdu 4494 Teamwork 最小费用最大流

Teamwork Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4494 Description Some locations in city A has been destroyed in the fierce battle. So the government decides to send some workers to repair these location

hdu 1533 Going Home 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533 On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need

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 1853 Cyclic Tour 最小费用最大流

题意:一个有向图,现在问将图中的每一个点都划分到一个环中的最少代价(边权和). 思路:拆点,建二分图,跑最小费用最大流即可.若最大流为n,则说明是最大匹配为n,所有点都参与,每个点的入度和出度又是1,所以就是环. /********************************************************* file name: hdu1853.cpp author : kereo create time: 2015年02月16日 星期一 17时38分51秒 *******

hdu 1533 Going Home 最小费用最大流 入门题

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

HDU 1533--Going Home【最小费用最大流 &amp;&amp; 模板】

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

POJ 2195 &amp; HDU 1533 Going Home(最小费用最大流)

题目链接: POJ:http://poj.org/problem?id=2195 HDU:http://acm.hdu.edu.cn/showproblem.php?pid=1533 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically,

hdu 4067 Random Maze 最小费用最大流

题意: 给出n个点,m条边,入口s和出口t,对于每条边有两个值a,b,如果保留这条边需要花费:否则,移除这条边需要花费b. 题目要求用最小费用构造一个有向图满足以下条件: 1.只有一个入口和出口 2.所有路都是唯一方向 3.对于入口s,它的出度 = 它的入度 + 1 4.对于出口t,它的入度 = 它的出度 + 1 5.除了s和t外,其他点的入度 = 其出度 最后如果可以构造,输出最小费用:否则输出impossible. 思路: 表示建图太神..给个博客链接:http://www.cppblog.

HDU 1853--Cyclic Tour【最小费用最大流 &amp;&amp; 有向环最小权值覆盖 】

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