版权声明:不转不是中国人!(滑稽) https://blog.csdn.net/xym_CSDN/article/details/80847391
回归后的第一篇blog,康复打板中
这种题我做了2个多小时。。(反正我现在已经失去对题目难度的辨识了)
很容易想到
的状压做法,但是超时,考虑优化,想到不正确的贪心思路,即n轮中每次都取最大概率,而最优解中不一定取这次的最大概率,但是会“退而求其次”,找没被选的里面的最优,而被选的最多为n-1个,所以对于每轮来说只要挑出概率前
大的,最优解一定在其中选择,这样数据规模就从
减小到了至多
除此以外,对数据取log后变为求累加的最大值,所以也可以建图后费用流
注意:数据给出的是对手获胜的概率,不是自己的
状压DP
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ID,cnt;
int bit[1030],id[100005];
double data[11][100005],a[11][105],f[2][1030];
bool vis[100005];
bool cmp(int x,int y){return data[ID][x]>data[ID][y];}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) scanf("%lf",data[i]+j),data[i][j]=1.0-data[i][j];
for (int j=1,i=1;i<(1<<n);i<<=1,++j) bit[i]=j;
for (int j=1;j<=m;++j) id[j]=j,vis[j]=0;
cnt=0;
for (ID=1;ID<=n;++ID)
{
sort(id+1,id+m+1,cmp);
for (int j=1;j<=n;++j)
if (!vis[id[j]])
{
vis[id[j]]=1;
++cnt;
for (int k=1;k<=n;++k) a[k][cnt]=data[k][id[j]];
}
}
for (int i=0;i<(1<<n);++i) f[0][i]=0;
f[0][0]=1;
for (int x=1,i=1;i<=cnt;++i,x^=1)
for (int k,j=0;j<(1<<n);++j)
{
f[x][j]=f[x^1][j];
for (k=j;k;k^=(k&-k))
f[x][j]=max(f[x][j],f[x^1][j^(k&-k)]*a[bit[k&-k]][i]);
}
printf("%.15lf\n",f[cnt&1][(1<<n)-1]);
}
}
费用流
#include<cstdio>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,ID,cnt,S,T,tot;
int id[100005],up[205],first[205];
double data[11][100005],a[11][105],dis[205];
bool vis[100005];
bool cmp(int x,int y){return data[ID][x]>data[ID][y];}
struct edge{
int v,next;
char w;
double c;
}e[10005];
void add(int x,int y,int z,double c)
{
e[++tot].v=y;e[tot].next=first[x];e[tot].w=z;e[tot].c=c;first[x]=tot;
e[++tot].v=x;e[tot].next=first[y];e[tot].w=0;e[tot].c=-c;first[y]=tot;
}
queue<int>q;
bool spfa()
{
for (int i=1;i<=T;++i) dis[i]=1e9;
q.push(S);vis[S]=1;
for (int x;!q.empty();q.pop())
{
x=q.front();
for (int i=first[x];i;i=e[i].next)
if (e[i].w&&dis[e[i].v]>dis[x]+e[i].c)
{
dis[e[i].v]=dis[x]+e[i].c;
up[e[i].v]=i;
if (!vis[e[i].v])
q.push(e[i].v),
vis[e[i].v]=1;
}
vis[x]=0;
}
return dis[T]<1e8;
}
double flow()
{
for (int i=up[T];i;i=up[e[i^1].v]) swap(e[i].w,e[i^1].w);
return dis[T];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j) scanf("%lf",data[i]+j),data[i][j]=1.0-data[i][j];
for (int j=1;j<=m;++j) id[j]=j,vis[j]=0;
cnt=0;
for (ID=1;ID<=n;++ID)
{
sort(id+1,id+m+1,cmp);
for (int j=1;j<=n;++j)
if (!vis[id[j]])
{
vis[id[j]]=1;
++cnt;
for (int k=1;k<=n;++k) a[k][cnt]=data[k][id[j]];
}
}
S=0;T=n+cnt+1;tot=1;
for (int i=S;i<=T;++i) vis[i]=first[i]=0;
for (int i=1;i<=n;++i) add(S,i,1,0);
for (int i=1;i<=cnt;++i) add(i+n,T,1,0);
for (int i=1;i<=n;++i)
for (int j=1;j<=cnt;++j) add(i,j+n,1,-log(a[i][j]));
double ans=0;
while(spfa()) ans+=flow();
printf("%.15lf\n",exp(-ans));
}
}