您的位置:首页 > 其它

USACO 4.4.2 Pollutant Control追查坏牛奶 题解与分析

2013-09-23 21:32 453 查看
Pollutant Control追查坏牛奶译 by Twink

描述

你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶。很不幸,你发现这件事的时候,有三聚氰胺的牛奶已经进入了送货网。这个送货网很大,而且关系复杂。你知道这批牛奶要发给哪个零售商,但是要把这批牛奶送到他手中有许多种途径。送货网由一些仓库和运输卡车组成,每辆卡车都在各自固定的两个仓库之间单向运输牛奶。在追查这些有三聚氰胺的牛奶的时候,有必要保证它不被送到零售商手里,所以必须使某些运输卡车停止运输,但是停止每辆卡车都会有一定的经济损失。你的任务是,在保证有三聚氰胺的牛奶不送到零售商的前提下,制定出停止卡车运输的方案,使损失最小。

格式

PROGRAM NAME: milk6INPUT FORMAT:(file milk6.in) 第一行: 两个整数N(2<=N<=32)、M(0<=M<=1000), N表示仓库的数目,M表示运输卡车的数量。仓库1代 表发货工厂,仓库N代表有三聚氰胺的牛奶要发往的零售商。 第2..M+1行: 每行3个整数Si,Ei,Ci。其中Si,Ei表示这 辆卡车的出发仓库,目的仓库。Ci(0 <= C i <= 2,000,000) 表示让这辆卡车停止运输的损失。OUTPUT FORMAT:(file milk6.out) 第1行两个整数C,T。C表示最小的损失,T表示要停止的最少卡车数。接下来T行表示你要停止哪几条线路。如果有多种方案使损失最小,输出停止的线路最少的方案。如果仍然还有相同的方案,请选择开始输入顺序最小的。

SAMPLE INPUT

4 5
1 3 100
3 2 50
2 4 60
1 2 40
2 3 80

SAMPLE OUTPUT

60 1
3
【分析】:
本题思路为网络流求最大流和最小割边集。首先加流量。为了构造解,我记录了输入的顺序并对边的大小进行了排序<排序按边权从大到小排序,这一步主要是为了后面求最小割>,然后先求一遍最大流S,然后枚举去掉每一条边<设边权值为T>,然后求当前最大流X,若S=T+X,则该边在最小割边集中,将该边从图中去掉,S=X。注意,每次DINIC后若用同一个数组记流量,需在DINIC后还原。
【代码】:
/*
ID:csyzcyj1
PROG:milk6
LANG:C++
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAXN 33
#define MAXM 1001
#define IMAX 2147483647
struct road{int f,t,num;long long c;};
road a[MAXM];
int N,M,tot=0,ans1=0,ans[MAXM];
long long map[MAXN][MAXN],basic=0,old[MAXN][MAXN];
long long d[MAXN];
vector<int> point[MAXN];
bool vis[MAXN];
bool cmp(road X,road Y)
{
if(X.c==Y.c)
return X.num<Y.num;
else return X.c>Y.c;
}
bool build()
{
long long q[MAXN];
int tot1=0;
for(int i=0;i<=N+1;i++)
d[i]=IMAX;
q[++tot1]=1;
d[1]=0;
for(int i=1;i<=tot1;i++)
{
int now=q[i];
for(int j=0;j<(int)point[now].size();j++)
{
int next=point[now][j];
if(map[now][next] && d[now]+1<d[next])
{
d[next]=d[now]+1;
q[++tot1]=next;
if(next==N)   return true;
}
}
}
return false;
}
long long DINIC(int now,long long flow)
{
long long now1;
if(flow==0)   return 0;
if(now==N)    return flow;
for(int i=0;i<(int)point[now].size();i++)
{
int next=point[now][i];
if(d[now]+1==d[next] && (now1=DINIC(next,min(flow,map[now][next]))))
{
map[now][next]-=now1;
map[next][now]+=now1;
return now1;
}
}
return 0;
}
void map_reset()
{
for(int i=0;i<=N;i++)
for(int j=0;j<=N;j++)
map[i][j]=old[i][j];
}
void work()
{
long long use=0;
while(build())
{
while(use=DINIC(1,IMAX))
{
basic+=use;
}
}
printf("%lld ",basic);

for(int i=1;i<=M;i++)
{
long long ansnow=0;
map_reset();//由于每次DINIC后map值会变,因此需在每次DINIC后还原原始值
map[a[i].f][a[i].t]-=a[i].c;
while(build())
{
while(use=DINIC(1,IMAX))
{
ansnow+=use;
}
}
if(basic-ansnow==a[i].c)
{
ans[++tot]=a[i].num;
old[a[i].f][a[i].t]-=a[i].c;
basic=ansnow;
}
}
}
int main()
{
freopen("milk6.in","r",stdin);
freopen("milk6.out","w",stdout);
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
scanf("%d%d%d",&a[i].f,&a[i].t,&a[i].c);
a[i].num=i;
map[a[i].f][a[i].t]+=a[i].c;//加流量
old[a[i].f][a[i].t]+=a[i].c;
point[a[i].f].push_back(a[i].t);
}
sort(a+1,a+1+M,cmp);
work();
sort(ans+1,ans+1+tot);
printf("%d\n",tot);
for(int i=1;i<=tot;i++)
printf("%d\n",ans[i]);
//system("pause");
return 0;
}
【测评信息】:
TASK: milk6
LANG: C++
Compiling...
Compile: OK
Executing...
   Test 1: TEST OK [0.011 secs, 3556 KB]
   Test 2: TEST OK [0.011 secs, 3556 KB]
   Test 3: TEST OK [0.011 secs, 3556 KB]
   Test 4: TEST OK [0.011 secs, 3556 KB]
   Test 5: TEST OK [0.043 secs, 3556 KB]
   Test 6: TEST OK [0.011 secs, 3556 KB]
   Test 7: TEST OK [0.011 secs, 3556 KB]
   Test 8: TEST OK [0.011 secs, 3556 KB]
   Test 9: TEST OK [0.032 secs, 3556 KB]
   Test 10: TEST OK [0.076 secs, 3556 KB]
   Test 11: TEST OK [0.011 secs, 3556 KB]
   Test 12: TEST OK [0.011 secs, 3556 KB]
All tests OK.
YOUR PROGRAM ('milk6') WORKED FIRST TIME!  That's fantastic
-- and a rare thing.  Please accept these special automated
congratulations.
Keep up the good work!
Thanks for your submission!
 
转载注明出处:http://blog.csdn.net/u011400953

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: