题目大意:
火星人入侵地球,他们降落的区域为一个n*m的矩形兵工厂,在这个区域行顶点和列顶点处有激光束,激光束一次能消灭一排或一列的敌人。为了消灭所有入侵的火星人,求最小的花费。每安装一个激光束都有一个权值,花费所有激光束权值的积。
思路:
如果不考虑到点权值,如POJ3041,每个点权值都为1,也就是求最大二分图匹配了。
用匈牙利或者网络流都很好做的。
so... 但是这题求的是最优点权覆盖,怎么做呢....
可以发现这题还是个二分图..
咱们把行定为[1,n]列点定为[n+1,n+m],这样构造二分图。
源点与行点连边,容量为行的点权,列点与汇点连边,容量为列的点权,做到限制流量。
边为行与列点连边,容量INF。
咱们要消灭所有的敌人。也就是在这个图中每条边的两顶点之一满流。
怎样保证两顶点之一满流呢?求最大流就OK了。
因为:如果有边e(u,v)的顶点u,v都没有满流,则一定可以增大流量。
为啥是两顶点之一满流?
因为当行点满流,则在该行上的所有敌人全部消灭。
当列点满流,则在该列上的所有敌人全部消灭。
所以要消灭相应敌人则必须是该敌人代表的边e(u,v)至少两顶点之一满流。
这里明明是+法,咋来的乘法??
我也没懂... 看网上的解法...
大概是这么个意思:
a*b*c*d=e^ln(a*b*c*d)=e^( ln(a)+ln(b)+ln(c)+ln(d) );
ln()在C++里是log()
e^x在C++里是exp()
综上为题解.....
code:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#define MN 111
#define CC(a) memset( a,0,sizeof(a) )
#define FF(i,a) for( int i=0;i<a;i++ )
#define INF 0x3FFFFFFF
#define eps 1e-7
using namespace std;
double maze[MN][MN];
int gap[MN],cur[MN],pre[MN],dis[MN];
int m,n,l,s,t;
double min( double a,double b ){ return a<b?a:b; }
void setG()
{
FF(i,MN)FF(j,MN)
maze[i][j]=0;
s=0,t=n+m+1;
for( int i=1;i<=n;i++ )
{
scanf( "%lf",&maze[s][i] );
maze[s][i]=log(maze[s][i]);
}
for( int i=1;i<=m;i++ )
{
scanf( "%lf",&maze[i+n][t] );
maze[i+n][t]=log(maze[i+n][t]);
}
int u,v;
FF( i,l )
{
scanf( "%d%d",&u,&v );
maze[u][v+n]=INF;
}
}
double sap()
{
CC(cur),CC(dis),CC(gap);
int u=pre[s]=s;
double maxflow=0,aug=INF;
gap[0]=t+1;
while( dis[s]<=t ){
loop:
for( int v=cur[u];v<=t;v++ )
if( maze[u][v]>0&&dis[u]==dis[v]+1 )
{
//printf( "%d",u );
//ge/char();
pre[v]=u;
cur[u]=v;
aug=min(aug,maze[u][v]);
u=v;
if( v==t )
{
maxflow+=aug;
//printf( "%lf!!",aug );getchar();
for( u=pre[u];v!=s;v=u,u=pre[u] )
maze[u][v]-=aug,maze[v][u]+=aug;
aug=INF;
}
goto loop;
}
int mind=t;
for( int v=0;v<=t;v++ )
if( maze[u][v]>0&&mind>dis[v] )
{
cur[u]=v;
mind=dis[v];
}
if( --gap[dis[u]]==0 )break;
gap[dis[u]=mind+1]++;
u=pre[u];
}
return maxflow;
}
int main()
{
int T;
scanf( "%d",&T );
while( T-- )
{
scanf( "%d%d%d",&n,&m,&l );
setG();
double ans=sap();/*
double ans=1;
for( int i=1;i<=n;i++ )
if( maze[i][s]>0 )
ans*=maze[i][s];*/
printf( "%.4lf\n",exp(ans) );
}
return 0;
}