您的位置:首页 > 其它

POJ3308

2016-08-05 15:33 274 查看
Problem : Paratroopers

Description : 有一个矩阵,里面有一些伞兵,现在每一行都有价格不一样的炮弹,它能打一整行或一整列的目标,现在问你至少要多少花费才能消灭所有的伞兵。

Solution : 最小点权覆盖集。这个题和POJ3041差不多,那个题目也可以用今天这种网络流的方法做,只不过是改一下边的权值就好了(改成1)。伞兵就看成二分图中边。那么从源点到每行连一条边,权值为买这种炮弹的花费,同理,汇点也是一样,然后,把伞兵所在的行与列连边,权值为无穷大。最后跑一遍网络最大流求得最小割也就求得了最小点权和。

Code(C++) :

#include <stdio.h>
#include <string.h>
#include <math.h>

#include <iostream>
#include <string>
#include <queue>

#define MIN(a,b) ((a)>(b)? (b):(a))

using namespace std;

const int SIZE=20000+50;
const double INF=0x3f3f3f3f;

struct Node{
int u,v;
double cap;
Node(){}
Node(int U,int V,double Cap):
u(U),v(V),cap(Cap){}
};

int src,des;
vector<int> G[SIZE];
Node e[SIZE*100*4];
int d[SIZE];
int cur[SIZE];
int n;
int top;

int R,C,M;

void addedge(int u,int v,double cap)
{
G[u].push_back(top);
e[top++]=Node(u,v,cap);
G[v].push_back(top);
e[top++]=Node(v,u,0);
}

void build()
{
int i,j;
for(i=0;i<SIZE;i++)
G[i].clear();
top=0;
scanf("%d%d%d",&R,&C,&M);
n=R+C;
src=0<
4000
/span>;
des=n+1;
double tmp;
for(i=1;i<=R;i++)
scanf("%lf",&tmp),
addedge(src,i,log(tmp));
for(i=1;i<=C;i++)
scanf("%lf",&tmp),
addedge(i+R,des,log(tmp));
int x,y;
for(i=1;i<=M;i++)
scanf("%d%d",&x,&y),
addedge(x,y+R,INF);
}

bool bfs(int src,int des)
{
memset(d,-1,sizeof(d));
queue<int> que;
que.push(src);
d[src]=0;
while(!que.empty()){
int now=que.front();
que.pop();
for(int i=0;i<G[now].size();i++){
Node &tmp=e[G[now].at(i)];
if(tmp.cap>0&&d[tmp.v]==-1)
d[tmp.v]=d[now]+1,
que.push(tmp.v);
}
}
return d[des]>=0;
}

double dfs(int t,double sum,int des)
{
if(t==des||0.0==sum)
return sum;
double flow=0,f;
for(int &i=cur[t];i<G[t].size();i++){
Node &tmp=e[G[t].at(i)];
if(d[tmp.v]==d[t]+1&&(f=dfs(tmp.v,MIN(sum,tmp.cap),des))>0){
tmp.cap-=f;
e[G[t].at(i)^1].cap+=f;
sum-=f;
flow+=f;
if(0.0==sum)
break;
}
}
return flow;
}

double DINIC(int src,int des)
{
double sum=0;
while(bfs(src,des)){
memset(cur,0,sizeof(cur));
sum+=dfs(src,INF,des);
}
return sum;
}

void work()
{
build();
printf("%.4f\n",exp(DINIC(src,des)));
}

int main()
{
//freopen("in.data","r",stdin);
int T;
scanf("%d",&T);
while(T--)
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: