POJ -2391 Ombrophobicウシ(+フロイド+二部ネットワーク・フロー)

Ombrophobicウシ

時間制限:  1000ミリ秒   メモリ制限:  65536kも
合計提出:  21425   受け入れ:  4593

説明

FJの牛は本当にそんなに雨で捕まるの単なる思考は、彼らのひづめに振る作ること濡れる嫌い。彼らは雨が近づいているとき、彼らは知っているように農場で雨のサイレンを置くことにしました。彼らは雨が始まる前に、すべての牛は避難所に得ることができるように雨の避難計画を作成する予定。天気予報は、しかし、常に正しいではありません。誤報を最小にするために、彼らはまだ、すべての牛は、いくつかの避難所に到達するのに十分な時間を与えながら可能な限り遅くとしてサイレンを鳴らしたいです。 

ファームは、牛が放牧たF(1 <= F <= 200)のフィールドを有します。P(1 <= P <= 1500)パスのセットは、それらを接続します。牛の任意の数のいずれかの方向にパスを横断することができるようにパスは、広いです。 

農場のフィールドの中には、牛が自分自身を保護することができ、その下雨の避難所を持っています。単一避難所はすべての牛を保持することができない場合がありますので、これらのシェルターは、限られたサイズのものです。フィールドは、パスに比べて小さく、牛が横断するための時間を必要としません。 

雨がサイレンは、すべての牛は、いくつかの避難所に行くことができるように聞こえなければならないことを開始するまでに時間の最小量を計算します。

入力

* 1行目:二スペースで区切られた整数:FとP 

*行2..F + 1:フィールドを記述する二つのスペースで区切られた整数。最初の整数(範囲:0..1000)は、そのフィールド内の牛の数です。第整数(範囲:0..1000)は、そのフィールド内の避難所が保持できる牛の数です。行I + 1フィールドをIについて説明します。 

*線F + 2..F + P + 1:パスを記述する三つのスペースで区切られた整数。第一および第二の整数(両方範囲1..F)はパスによって接続されたフィールドを言います。第三の整数(範囲:1..1,000,000,000)は、任意の牛がそれを通過するのにかかるどのくらいです。

出力

* 1行目:彼らは最適に彼らのルートを計画して想定、避難所の下に取得するために、すべての牛のために必要な最小時間。それは可能ではない、すべての牛は、避難所、出力の下に取得するために場合は「-1」。

サンプル入力

3 4 
7 2 
0 4 
2 6 
1 2 40 
3 2 70 
2 3 90 
1 3 120

サンプル出力

110

ヒント

OUTPUTの詳細: 

110時間単位で、フィールド1から2頭がそのフィールドにシェルターの下に入ることができ、フィールド1から4頭の牛、フィールド2にシェルターの下に入ることができ、1頭の牛、フィールド3に到達し、そこから牛に参加することができフィールド3にある避難所の下のフィールドには、避難所の下にあるすべての牛を取得する他の計画がありますが、どれもより少ない110時間単位でそれを行いません。

ソース

USACO 2005月ゴールド

 

質問の意味:

そこn個のブロック草、各牛に草があり、ポイント数は、シールド牛の数を雨することができます

そして、M草の両側のいずれかに接続されていない、すべての道は、固定長であり、雨が降るかどうか尋ね、すべての牛最短時間でに取得する方法

最短時間を尋ねる;、その後、出力が-1でない場合は、すべての牛は、雨のポイントに来てみましょう。

 

アイデア:

草原ノード、道路の縁、長さの道路辺の長さ。

フロイド量算出任意の2点間の最短距離アルゴリズムは、応答半分、ネットワーク・フローを実行して、牛の流れ

最大流量場合> =いくつかの時間を短縮することができることを示している牛の数が、それ以外の場合に増加しました。

 

ネットワークフロー図: 

[i]は草原牛の間で流れるように、スーパーソースを与えていません 

私はINF流れ」は、それぞれ追加のポイント仮想化草 

「(DISの流量i、j)の間の」I草の牧草地や仮想J。

スーパーの合流点との間の草地トラフィック(牛の数を遮蔽することができる)シェルター[I]

 

データが長いlong int型で破裂することに注意してください 

[コード]

//#include <bits/stdc++.h>
#include <iostream>
#include <queue>
#include <string.h>
#include <stdio.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)

typedef long long ll;
const int maxn = 1e5+10;
const int mod =1e9+7;
const int inf = 0x3f3f3f3f;
const ll INF = 1e16;
using namespace std;
const int NMAX = 420;
const int EMAX = 82000;


int n,m;
int ne ,head[maxn];
int num[maxn],start,END,cnt,sum;
int cow[NMAX],shelter[NMAX];
ll mp[NMAX][NMAX];

struct node{
    int v,w,next; //u  v 从 u-v 权值为w
}edge[maxn];

void init()
{
    cnt = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
	/*
	根据题意建立有向图或无向图, 有向图反路0
	无向图反路一样
	*/
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;

    edge[cnt].v = u;
    edge[cnt].w = 0;
    edge[cnt].next = head[v];
    head[v] = cnt++;
}
int bfs()
{
    queue<int>Q;
    memset(num,0,sizeof(num));
    num[start] = 1;
    Q.push(start);
    while(!Q.empty())
    {
        int t = Q.front();
        Q.pop();
        if(t==END)
            return 1;
        for(int i=head[t];i!=-1;i=edge[i].next)// 链式前向星访问找增广路
        {
            int t1 = edge[i].v;//下一个节点
            int t2 = edge[i].w;// 当前点 的流
            if(t2&&num[t1]==0)// 当前点存在 并且下一个点没有访问
            {
                num[t1]=num[t]+1;// 点=1
                if(t1==END)//  结束
                    return 1;// 存在
                Q.push(t1);
            }
        }
    }
    return 0;
}
int dfs(int u,int maxflow)
{
    if(u==END)
        return maxflow;
    int res = 0;  //从当前u点流出的流量
    for(int i = head[u];i!=-1;i = edge[i].next)
    {
        int t1 = edge[i].v;// 下一个节点
        int t2 = edge[i].w;// 当前节点的流
        if(t2&&num[t1] == num[u]+1)
        {
            int temp = dfs(t1,min(maxflow-res,t2));// 选择流 小的一部分
            edge[i].w-=temp;// 正向减少
            edge[i^1].w+=temp;//反向增加
            res += temp;
            if(res==maxflow)
                return res;//已达到祖先的最大流,无法再大,剪枝
        }
    }
    if(!res)
        num[u] = -1;//此点已无流,标记掉
    return res;
}
ll Dinic(int s,int ed)
{
    ll ans = 0;
    while(bfs()) //有增广路
    {
        ans+=dfs(s,inf);
    }
    return ans;
}

void floyd()
{
	for(int  k = 1; k <= n ;k++)
	{
		for(int  i = 1 ; i <= n;i++)
		{
			for(int j = 1 ;j <= n;j++)	
			{ 
				if( mp[i][k] + mp[k][j] <  mp[i][j])
				{
					mp[i][j]  = mp[i][k] + mp[k][j];
				}
			}
		}
	}
}
int main(int argc, char const *argv[])
{
	int u,v;
	ll sum,w;
	while(~scanf("%d %d",&n,&m))
	{
		END = 2*n+1;start = 0;
		
		for(int i = 1 ;i <= n ; i++)
			for(int j = 1 ;j <= n ; j++)
					mp[i][j] = INF;
		sum =  0;
		for(int i = 1; i <= n ; i++)
		{
			scanf("%d %d",&cow[i],&shelter[i]);
			sum += cow[i];
		}
		
		while(m--)
		{
			scanf("%d %d %lld",&u,&v,&w);
			if( w < mp[u][v] )
			{
				mp[u][v] = mp[v][u] = w;
			}
		}
		floyd();

		ll mid ,low = 0, high = INF-1 ,ans = -1;
		
		while( low < high)
		{
			mid = (low + high )>>1;
			init();
			for(int i = 1 ;i <= n;i++)
			{
				addedge(0,i,cow[i]);
				addedge(i,i+n,inf);
				addedge(i+n,2*n+1,shelter[i]);
				for( int j = i+ 1 ; j <= n ;j++)
				{
					if(mp[i][j] <= mid)
					{
						addedge(i,j+n,inf);
						addedge(j,i+n,inf);
					}
				}
			}
			ll te = Dinic(0,2*n+1);
			//cout<<te<<" Dinic "<<sum<<" "<<mid<<endl;
			if(  te>= sum)
			{
				ans = mid;
				high = mid;
			}
			else 
				low = mid + 1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
/*
	3 4
	7 2
	0 4
	2 6
	1 2 40
	3 2 70
	2 3 90
	1 3 120
 */

 

公開された372元の記事 ウォン称賛89 ビュー23万+

おすすめ

転載: blog.csdn.net/sizaif/article/details/83110155