您的位置:首页 > 理论基础 > 计算机网络

hdu-4309(网络流)

2012-07-21 20:59 316 查看
2012多校联合赛第一场,第十题。

先不考虑可以修复的桥的性质, 则可以将模型简化为n个点的人通过有通过人数上限的有向边,到达一些有人数上限的特殊的边(隧道)。

可以建立最大流模型来求解, 增加一个源点S,和一个汇点T。 S向每个有人的点,连一条容量为人数的边, 图中普通的u->v的有向边,连一条u->v的流量为无穷的边, 桥的流量则为1。 对于隧道,每个隧道可以虚拟出一个点,如u->v的隧道,可以虚拟一个点x,连接u->x,x->v的流量无穷的边, 和x->T的流量为隧道人数上限的边, 求解最大流即可得到最大人数。

现在考虑桥的问题,题目中说明了桥最多只有12座,故可以2^12枚举修复哪些桥,不修复的桥没有花费,连接的边流量为1,要修复的桥则计算花费,边的流量为无穷,这样进行2^12次最大流就可以得到最优解。

看了题解后,建图,1Y。

2^12枚举,对桥建边很戏剧,用递归,很好玩。

发现我现在的编程状态很好,200行编下来,基本上想到什么就能编出来什么,网络流,递归,枚举。。以后只要相信自己就好。

相信自己的编码能力!!!

View Code

/*
Problem : 4309 ( Seikimatsu Occult Tonneru )     Judge Status : Accepted
RunId : 6291376    Language : G++    Author : 2010201211
Time : 1687MS Memory : 608K
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define E 30000
#define V 1102
#define inf 0xffff
struct Edge{
int u,v,c,next;
}edge[E];
int n,m,cnt;
int cou;
int dist[V];
int head[V];
int que[V];
int sta[V];
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c){
edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c;
edge[cnt].next=head[u];head[u]=cnt++;

edge[cnt].u=v;edge[cnt].v=u;edge[cnt].c=0;
edge[cnt].next=head[v];head[v]=cnt++;
}
int dinic(int s,int t){
int ans=0;
while(true){
int left,right,u,v;

memset(dist,-1,sizeof(dist));
left=right=0;
que[right++]=s;
dist[s]=0;

while(left<right){
u=que[left++];
for(int k=head[u];k!=-1;k=edge[k].next){
u=edge[k].u;
v=edge[k].v;
if(edge[k].c>0 && dist[v]==-1){
dist[v]=dist[u]+1;
que[right++]=v;
if(v==t){
left=right;
break;
}
}
}
}

if(dist[t]==-1) break;

int top=0;
int now=s;
while(true){
if(now!=t){
int k;
for(k=head[now];k!=-1;k=edge[k].next){
if(edge[k].c > 0 && dist[edge[k].u]+1==dist[edge[k].v]) break;
}
if(k!=-1){
sta[top++]=k;
now=edge[k].v;
}
else{
if(top==0) break;
dist[edge[sta[--top]].v]=-1;
now=edge[sta[top]].u;
}
}
else{
int flow=inf,ebreak;
for(int i=0;i<top;i++){
if(flow>edge[sta[i]].c){
flow=edge[sta[i]].c;
ebreak=i;
}
}
ans+=flow;
for(int i=0;i<top;i++){
edge[sta[i]].c-=flow;
edge[sta[i]^1].c+=flow;
}
now = edge[sta[ebreak]].u;
top = ebreak;
}
}
}
return ans;
}
int r,b,t;
int p[V];
struct T{
int u,v,c;
}road[E],bridge[E],tunnel[E];
bool fb[12];
struct R{
int num,cost;
}res[5000];
void build(){
init();
for(int i=1;i<=n;i++){
addedge(0,i,p[i]);
}
for(int i=0;i<r;i++){
addedge(road[i].u,road[i].v,inf);
}
for(int i=0;i<t;i++){
addedge(tunnel[i].u,n+i+1,inf);
addedge(n+i+1,tunnel[i].v,inf);
addedge(n+i+1,n+t+1,tunnel[i].c);
}
}

void dfs(int s){//2^12枚举,对桥建边。
if(s==b){
int sum=0;
build();
for(int i=0;i<b;i++){
if(fb[i]==0){
addedge(bridge[i].u,bridge[i].v,1);
sum+=0;
}
else{
addedge(bridge[i].u,bridge[i].v,inf);
sum+=bridge[i].c;
}
}
res[cou].num=dinic(0,n+t+1);
res[cou++].cost=sum;
return ;
}
fb[s]=0;
dfs(s+1);
fb[s]=1;
dfs(s+1);
}

int main()
{
//freopen("in.txt","r",stdin);
int a,bb,c,d;
while(cin >> n >> m){
for(int i=1;i<=n;i++){
cin >> p[i];
}
r=b=t=0;
for(int i=1;i<=m;i++){
cin >> a >> bb >> c >> d;
if(d<0){
tunnel[t].u=a;
tunnel[t].v=bb;
tunnel[t++].c=c;
}
if(d==0){
road[r].u=a;
road[r++].v=bb;
}
if(d>0){
bridge[b].u=a;
bridge[b].v=bb;
bridge[b++].c=c;
}
}
memset(fb,0,sizeof(fb));
for(int i=0;i<5000;i++){
res[i].cost=0;
res[i].num =0;
}

cou=0;
dfs(0);
int minc=inf,maxc=-1;
for(int i=0;i<cou;i++){
if(res[i].num>maxc){
maxc=res[i].num;
}
}
for(int i=0;i<cou;i++){
if(res[i].num==maxc){
if(res[i].cost<minc){
minc=res[i].cost;
}
}
}
if(maxc==0) printf("Poor Heaven Empire\n");
else printf("%d %d\n",maxc,minc);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: