您的位置:首页 > 其它

HDU_5045_Contest(状态压缩or最小费用最大流)

2014-09-28 17:37 323 查看
题型:动态规划OR网络流

题意:

n个队员做m道题,第i个小时做第i个题目。Pij表示第i个队员能做出第j个题目的概率。

在任意时刻,任意两个队员的编程时间之差不允许超过1个小时。

问能做出最多题目的期望。

分析:

题目,最多10个人做1000道题。

根据题目的限制条件,可以发现,可行方案的队员序列必须是每n个题目由n个不同的队员做,即队员的全排列。

例如3个人做5道题,12312就是合法的,122321是不合法的。

这样就可以讲问题缩小了,只需要对每n个题目进行求解最优解,如果暴力枚举全排列,复杂度10!。

方法一:

采用状态压缩,复杂度2^10,妥妥的A了。

对于m%n != 0,需要对剩余的部分处理一下。我懒得处理了,于是直接后面用0补全,变成整整的n/m+1部分,简单粗暴效果好。

方法二:

采用费用流。

由于每n个题由n个不同的人做,所以很容易看出是二分图最大权匹配问题。可以采用KM算法,我用的是费用流,源点到队员流量为1,费用为0;队员到各个题目的流量为1,费用为对应概率取负;题目到汇点流量为1,费用为0.

跑n/m+1边费用流。

注意数组开的稍微大一点,我数组开的感觉差不多,却多次TLE和RE,不知为毛。开大一点就A了。

代码:

状态压缩:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;

int n,m;
double p[16][1024];

double dp[1<<10];

void init(){
for(int i=0;i<10;i++){
for(int j=0;j<1024;j++){
p[i][j] = 0.00;
}
}
}

int ONE(int x){
int num = 0;
while(x){
if(x&1) num ++;
x >>= 1;
}
return num;
}

int main(){
int _;
int Cas = 0;
scanf("%d",&_);
while(_--){
scanf("%d%d",&n,&m);
init();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%lf",&p[i][j]);
}
}
printf("Case #%d: ",++Cas);

int part = m/n;
if(m%n!=0){
part++;
}

//        printf("part = %d\n",part);

double ans = 0.0;
int all = (1<<n);

for(int op=0;op<part;op++){
//                cout<<"*****************"<<endl;
int s = op * n;//每一部分第一个位置
mt(dp,0);
for(int i=0;i<all;i++){
int yi = ONE(i);
if(yi>=n) continue;
for(int j=0;j<n;j++){
if((i>>j)&1) continue;
//如果这一位是0
int next = i|(1<<j);
dp[next] = max(dp[next],dp[i]+p[j][yi+s]);
}
}
ans += dp[all-1];
}

printf("%.5f\n",ans);

}
return 0;
}


费用流:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>

#define inf 0x3f3f3f3f
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;

int n,m;
double p[16][1024];

class MaxFlowMinCost { ///最小费用最大流 o(ME)
typedef int typef;///流量的类型
typedef double typec;///费用的类型
static const int ME=1010;///边的个数
static const int MV=100;///点的个数
queue<int> q;
int cur[MV],pre[MV];
bool used[MV],sign[MV];
typef flow;
typec cost,dist[MV];
bool spfa(int s,int t) {
mt(used,0);
mt(sign,0);
mt(dist,0);
used[s]=sign[s]=true;
while(!q.empty()) q.pop();
q.push(s);
while(!q.empty()) {
int u=q.front();
q.pop();
used[u]=false;
for(int i=g.head[u]; ~i; i=g.e[i].next) {
if(g.e[i].flow<1) continue;
int v=g.e[i].v;
typec c=g.e[i].cost;
if(!sign[v]||dist[v]>dist[u]+c) {
dist[v]=dist[u]+c;
sign[v]=true;
pre[v]=u;
cur[v]=i;
if(used[v]) continue;
used[v]=true;
q.push(v);
}
}
}
return sign[t];
}
struct G {
struct E {
int v,next;
typef flow;
typec cost;
} e[ME];
int le,head[MV];
void init() {
le=0;
mt(head,-1);
}
void add(int u,int v,typef flow,typec cost) {
e[le].v=v;
e[le].flow=flow;
e[le].cost=cost;
e[le].next=head[u];
head[u]=le++;
}
} g;
public:
void init() {
g.init();
}
void add(int u,int v,typef flow,typec cost) {
g.add(u,v,flow,cost);
g.add(v,u,0,-cost);
}
void solve(int s,int t) {
flow=cost=0;
while(spfa(s,t)) {
int temp=t;
typef now=inf;
while(temp!=s) {
now=min(now,g.e[cur[temp]].flow);
temp=pre[temp];
}
flow+=now;
temp=t;
while(temp!=s) {
int id=cur[temp];
cost+=now*g.e[id].cost;
g.e[id].flow-=now;
g.e[id^1].flow+=now;
temp=pre[temp];
}
}
}
typef getflow() {
return flow;
}
typec getcost() {
return cost;
}
} gx;

int main() {
int _;
int Cas = 0;
scanf("%d",&_);
while(_--) {
scanf("%d%d",&n,&m);
mt(p,0);

//        for(int i=0;i<n;i++){
//            for(int j=0;j<m+10;j++){
//                p[i][j] = 0.0;
//            }
//        }

for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
scanf("%lf",&p[i][j]);
}
}

//        cout<<"*************"<<endl;
//        for(int i=0; i<n; i++) {
//            for(int j=0; j<m; j++) {
//                printf("%.2f ",p[i][j]);
//            }
//            puts("");
//        }
//        cout<<"*************"<<endl;

printf("Case #%d: ",++Cas);

int part = m/n;
if(m%n!=0) part++;

double ans = 0.0;

for(int op=0; op<part; op++) {
gx.init();
int S = 2*n+1;
int T = 2*n+2;
int st = op * n;
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
gx.add(i,j+n,1,-p[i][j+st]);
}
}
for(int i=0; i<n; i++) {
gx.add(S,i,1,0);
}
for(int i=0; i<n; i++) {
gx.add(i+n,T,1,0);
}
gx.solve(S,T);
ans -= gx.getcost();
}

printf("%.5f\n",ans);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: