题目大意:
火星人入侵地球,他们降落的区域为一个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; }