羅区P4237不毛の海

タイトル説明

海の島のNピース、石橋mに接続された島。いくつかは、彼らは非常に魅力的で、島にwzt報酬を植えています。整数KIその誘惑記述。そして傭兵がLSQいくつかの小さな島々があり、彼らは整数双方向で説明価格を、持っています。LSQは彼の傭兵を支払わなければならない彼は報酬を見つけるのに役立つでしょう。

価格は傭兵になっていません。各傭兵について、プロセスを見て、彼は座席の橋を渡りますが、このプロセスは、彼は、価格に加えて、彼が通過したすべてのブリッジの長さになります。

勇敢と勇敢されている傭兵が、獣の追放のプロセスは、人々は非常に不快になりますけれども残念ながら、橋の障壁、島のすべての席だけではなく、多くの野生の獣があります。このように、各傭兵のため、価格は(出発の島を含む)すべての彼のパス島で獣の数を追加します。

LSQ彼は彼の傭兵のそれぞれが行くべき報酬決定意思決定を行う必要があり、ここですべてを理解しています。LSQの目標は、すべての報酬を見つけて、最大の利益を得ることです。各傭兵は一度だけ雇いました。

収入のように定義:すべての報酬マイナスすべてのお金を過ごしたLSQの魅力

LSQの決定は非常に難しいので、彼はあなたを助けるためにNOI上AKを喜ばせるために持っていました。

入力形式

最初の行番号4、N(アイランドの合計数)、M(ブリッジの総数)、(LSQ傭兵の合計数)、B(賞金の合計)

次に、行数n、各獣上の島の数

uは、島の数及び接続ブリッジ長さw vで島の間の数を表し、wは3つの数字U、V、次のm行

次に行、各行番号2 Qiは、piは、iは価格チー傭兵数を表し、PI島号の初期位置であります

二つの数字のKi、気のその後B行、私はのKiに対する報酬誘惑、位置番号の気の島の数を表し、

出力フォーマット

あなたはすべての報酬を見つけることができた場合は、出力が「はい」、および出力の最大の満足の次の行を達成することができます。

あなたは、出力の次の行を見つけるために、すべての報酬、出力「いいえ」、そしてどのくらいの報酬アップを見つけることができない場合。

概念

一般的にはコストの流れ

最初のマップに建てられ、ソースがさえ各傭兵への1の容量、ゼロコスト面、もし、その人を雇うかどうかの代わりに、それぞれの傭兵は、彼がさえ彼の長い橋コスト+ +獣に報いる到達することができます数代表が到着した場合、コストはKIを稼ぐことができ、これらの値はSpfaを計算統一し、最後-ki側のコストで各報酬ポイントを再び1の偶数容量をシンクすることができ、(獣の音符開始点と終了点を計算する必要があります) 。

それはシンクの端に接続されている場合最後に、それぞれの報酬を横断し、それが今でトラフィックがないされ、それが報酬に到達することができることを示す、彼は最終的な出力に答えることで合意しました。

最後に、それ以外の答えが膨大になり、小さな島に傭兵でない場合は、DIS配列は億、その後もない側を、提供することに注意してください、私が知っているどのように私に聞かないでください

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define MAXN 100100
int n, m, cnt, a[MAXN], src, sink, A, B, pri[MAXN], z[MAXN];
int comu[MAXN], flag[MAXN], dis[MAXN], cnt2, k[MAXN], q[MAXN];
struct node
{
	int v, w, c;
	node *next, *rev;
}pool[2*MAXN], *h[MAXN], *comv[MAXN];
void addedge(int u, int v, int c, int w)
{
	node *p = &pool[++cnt], *q = &pool[++cnt];
	p->v = v; p->w = w; p->c = c; p->next = h[u]; p->rev = q; h[u] = p;
	q->v = u; q->w = -w;q->c = 0; q->next = h[v]; q->rev = p; h[v] = q;
}
queue<int> Q;
bool spfa()
{
	for(int i=1;i<=sink;i++) dis[i] = (1<<30);
	memset(flag, 0, sizeof(flag));
	Q.push(src);
	dis[src] = 0;
	flag[src] = 1;
	while(!Q.empty())
	{
		int u = Q.front();
		Q.pop();
		flag[u] = 0;
		for(node *p = h[u]; p; p = p->next)
		{
			if(p->c > 0 && dis[p->v] > dis[u] + p->w)
			{
				dis[p->v] = p->w + dis[u];
				comu[p->v] = u;
				comv[p->v] = p;
				if(flag[p->v] == 0)
				{
					Q.push(p->v);
					flag[p->v] = 1;
				}
			}
		}
	}
	if(dis[sink] < (1<<30)) return true;
	else return false;
}
int find()
{
	int Min = 100000000;
	int u = sink;
	while(u != src)
	{
		Min = min(Min, comv[u]->c);
		u = comu[u];
	}
	u = sink;
	while(u != src)
	{
		comv[u]->c -= Min;
		comv[u]->rev->c += Min;
		u = comu[u];
	}
	return Min;
}
int ans1, ans2;
void mincostflow()//费用流 
{
	int sim=0;
	while(spfa() == true)
	{
		sim = find();
		ans1 += sim;
		ans2 += (sim*dis[sink]);
	}
}
struct edge
{
	int v, w;
	edge *next;
}pool2[2*MAXN], *h2[MAXN];
void addedge2(int u, int v, int w)
{
	edge *p = &pool2[++cnt2], *q = &pool2[++cnt2];
	p->v = v; p->w = w; p->next = h2[u]; h2[u] = p;
	q->v = u; q->w = w; q->next = h2[v]; h2[v] = q;
}
void Spfa(int s)//求每个佣兵到其他岛的费用 
{
	for(int i=1;i<=n;i++) dis[i] = 100000000;
	memset(flag, 0, sizeof(flag));
	Q.push(s);
	dis[s] = a[s];//初值为起点野兽数 
	while(!Q.empty())
	{
		int u = Q.front();
		Q.pop();
		flag[u] = 0;
		for(edge *p = h2[u]; p; p = p->next)
		{
			if(dis[p->v] > p->w + a[p->v] + dis[u])//这里直接加上了野兽数 
			{
				dis[p->v] = p->w + a[p->v] + dis[u];
				if(flag[p->v] == 0)
				{
					Q.push(p->v);
					flag[p->v] = 1;
				}
			}
		}
	}
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&A,&B);
	src = 0; sink = n+ m + 1 + A + B;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	int u, v, w;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		addedge2(u, v, w);
	}
	for(int i=1;i<=A;i++) 
		scanf("%d%d",&pri[i],&z[i]);
	for(int i=1;i<=B;i++) 
		scanf("%d%d",&k[i],&q[i]);
	for(int i=1;i<=A;i++)
	{
		Spfa(z[i]);
		for(int j=1;j<=B;j++) 
			if(dis[q[j]] < 100000000) //必须要判,否则会被算在费用里 
				addedge(i, A+j, 1, dis[q[j]] + pri[i]);
	}
	for(int i=1;i<=A;i++)
		addedge(src, i, 1, 0);
	for(int i=1;i<=B;i++)
		addedge(i+A, sink, 1, -k[i]);
	mincostflow();
	int cnt3=0;
	for(int i=1+A;i<=A+B;i++)
	{
		for(node *p = h[i]; p; p = p->next)
		{
			if(p->v == sink && p->c == 0) cnt3++;//统计答案 
		}
	}
	if(cnt3 == B) printf("Yes\n%d\n",-ans2);
	else printf("No\n%d\n",cnt3);
 	
	return 0;
}

おすすめ

転載: www.cnblogs.com/tuihuaddeming/p/11620652.html