1. 程式人生 > >[LOJ2288][THUWC2017]大蔥的神力:搜尋+揹包DP+費用流+隨機化

[LOJ2288][THUWC2017]大蔥的神力:搜尋+揹包DP+費用流+隨機化

分析

測試點1、2:搜尋+剪枝。

測試點3:只有一個抽屜,直接01揹包。

測試點4、5:每個物品體積相同,說明每個抽屜能放下的物品個數固定,直接費用流。

測試點6:每個物品體積相近,經過驗證發現每個抽屜能放下的物品個數仍然固定,費用流。

測試點7:除了第一個物體,其他物體體積相同。所以可以列舉第一個物體放在哪個抽屜,然後費用流。

測試點8、9、10:隨機化貪心,如果不是人品爆發基本不可能過(博主沒過)。

程式碼

測試點3

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
    int x;scanf("%d",&x);return x;
}

const int MAXN=2005;
const int MAXS=10005;
int n,m,s,v[MAXN],w[MAXN];
int f[MAXN][MAXS],pre[MAXN][MAXS];
int ans[MAXN];

int main(){
    freopen("drawer3.in","r",stdin);
    freopen("drawer3.out","w",stdout);
    n=read(),m=read();
    rin(i,1,n) v[i]=read();
    s=read();
    rin(i,1,n) w[i]=read();
    rin(i,1,n) rec(j,s,v[i]){
        f[i][j]=f[i-1][j];
        pre[i][j]=j;
        if(f[i-1][j-v[i]]+w[i]>f[i][j]){
            f[i][j]=f[i-1][j-v[i]]+w[i];
            pre[i][j]=j-v[i];
        }
    }
    int now=s,pos=n;
    while(pos){
        if(pre[pos][now]<now) ans[pos]=1;
        now=pre[pos][now];
        pos--;
    }
    rin(i,1,n) printf("%d ",ans[i]);
    printf("\n");
    return 0;
}

測試點4、5、6

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <queue>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
    int x;scanf("%d",&x);return x;
}

const int MAXN=1005;
const int MAXM=205;
int n,m,S,T,mincost,v,c[MAXM],w[MAXN][MAXM],ecnt=1,head[MAXN+MAXM];
int dis[MAXN+MAXM],pre[MAXN+MAXM];
bool book[MAXN+MAXM];
std::queue<int> q;
struct Edge{
    int to,nxt,cap,ost;
}e[(MAXN+MAXM+MAXN*MAXM)<<1];

inline void add_edge(int bg,int ed,int cap,int ost){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    e[ecnt].cap=cap;
    e[ecnt].ost=ost;
    head[bg]=ecnt;
}

inline bool spfa(){
    memset(dis,0x3f,sizeof dis);
    while(!q.empty()) q.pop();
    dis[S]=0;
    q.push(S);
    book[S]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        trav(i,x){
            int ver=e[i].to;
            if(dis[ver]>dis[x]+e[i].ost&&e[i].cap){
                dis[ver]=dis[x]+e[i].ost;
                pre[ver]=i;
                if(!book[ver]){
                    q.push(ver);
                    book[ver]=1;
                }
            }
        }
        book[x]=0;
    }
    return dis[T]<1e9;
}

inline void upd(){
    int now=T,flow=1e9;
    while(now!=S){
        flow=std::min(flow,e[pre[now]].cap);
        now=e[pre[now]^1].to;
    }
    now=T;
    while(now!=S){
        e[pre[now]].cap-=flow;
        e[pre[now]^1].cap+=flow;
        now=e[pre[now]^1].to;
    }
    mincost+=flow*dis[T];
}

inline void ek(){
    while(spfa()) upd();
}

int main(){
    freopen("drawer6.in","r",stdin);
    freopen("drawer6.out","w",stdout);
    n=read(),m=read();
    S=n+m+1,T=S+1;
    rin(i,1,n){
        v=read();
        add_edge(S,i,1,0);
        add_edge(i,S,0,0);
    }
    rin(i,1,m){
        c[i]=read()/v;
        add_edge(n+i,T,c[i],0);
        add_edge(T,n+i,0,0);
    }
    rin(i,1,n) rin(j,1,m){
        w[i][j]=read();
        add_edge(i,n+j,1,-w[i][j]);
        add_edge(n+j,i,0,w[i][j]);
    }
    ek();
    rin(i,1,n){
        bool flag=0;
        trav(j,i){
            int ver=e[j].to;
            if(ver==S) continue;
            if(!e[j].cap){
                printf("%d ",ver-n);
                flag=1;break;
            }
        }
        if(!flag) printf("0 ");
    }
    printf("\n");
    return 0;
}

測試點7

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <queue>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
    int x;scanf("%d",&x);return x;
}

const int MAXN=1005;
const int MAXM=205;
int n,m,S,T,mincost,v,c[MAXM],w[MAXN][MAXM],ecnt=1,head[MAXN+MAXM];
int dis[MAXN+MAXM],pre[MAXN+MAXM];
bool book[MAXN+MAXM];
std::queue<int> q;
struct Edge{
    int to,nxt,cap,ost;
}e[(MAXN+MAXM+MAXN*MAXM)<<1];

inline void add_edge(int bg,int ed,int cap,int ost){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    e[ecnt].cap=cap;
    e[ecnt].ost=ost;
    head[bg]=ecnt;
}

inline bool spfa(){
    memset(dis,0x3f,sizeof dis);
    while(!q.empty()) q.pop();
    dis[S]=0;
    q.push(S);
    book[S]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        trav(i,x){
            int ver=e[i].to;
            if(dis[ver]>dis[x]+e[i].ost&&e[i].cap){
                dis[ver]=dis[x]+e[i].ost;
                pre[ver]=i;
                if(!book[ver]){
                    q.push(ver);
                    book[ver]=1;
                }
            }
        }
        book[x]=0;
    }
    return dis[T]<1e9;
}

inline void upd(){
    int now=T,flow=1e9;
    while(now!=S){
        flow=std::min(flow,e[pre[now]].cap);
        now=e[pre[now]^1].to;
    }
    now=T;
    while(now!=S){
        e[pre[now]].cap-=flow;
        e[pre[now]^1].cap+=flow;
        now=e[pre[now]^1].to;
    }
    mincost+=flow*dis[T];
}

inline void ek(){
    while(spfa()) upd();
}

int main(){
    freopen("drawer7.in","r",stdin);
    freopen("drawer7.out","w",stdout);
    n=read(),m=read();
    S=n+m+1,T=S+1;
    int v1=read();
    rin(i,2,n){
        v=read();
    }
    rin(i,1,m){
        c[i]=read();
    }
    rin(i,1,n) rin(j,1,m){
        w[i][j]=read();
    }
    int minpos=-1,umincost=0;
    rin(k,1,m){
        ecnt=1,mincost=0;
        memset(head,0,sizeof head);
        c[k]-=v1;
        mincost-=w[1][k];
        rin(i,2,n){
            add_edge(S,i,1,0);
            add_edge(i,S,0,0);
        }
        rin(i,1,m){
            add_edge(n+i,T,c[i]/v,0);
            add_edge(T,n+i,0,0);
        }
        rin(i,2,n) rin(j,1,m){
            add_edge(i,n+j,1,-w[i][j]);
            add_edge(n+j,i,0,w[i][j]);
        }
        ek();
        if(mincost<umincost){
            umincost=mincost;
            minpos=k;
        }
        c[k]+=v1;
    }
    ecnt=1,mincost=0;
    memset(head,0,sizeof head);
    rin(i,2,n){
        add_edge(S,i,1,0);
        add_edge(i,S,0,0);
    }
    rin(i,1,m){
        add_edge(n+i,T,c[i]/v,0);
        add_edge(T,n+i,0,0);
    }
    rin(i,2,n) rin(j,1,m){
        add_edge(i,n+j,1,-w[i][j]);
        add_edge(n+j,i,0,w[i][j]);
    }
    ek();
    if(mincost<umincost){
        umincost=mincost;
        minpos=0;
    }
    else{
        int k=minpos;
        ecnt=1,mincost=0;
        memset(head,0,sizeof head);
        c[k]-=v1;
        mincost-=w[1][k];
        rin(i,2,n){
            add_edge(S,i,1,0);
            add_edge(i,S,0,0);
        }
        rin(i,1,m){
            add_edge(n+i,T,c[i]/v,0);
            add_edge(T,n+i,0,0);
        }
        rin(i,2,n) rin(j,1,m){
            add_edge(i,n+j,1,-w[i][j]);
            add_edge(n+j,i,0,w[i][j]);
        }
        ek();
    }
    printf("%d ",minpos);
    rin(i,2,n){
        bool flag=0;
        trav(j,i){
            int ver=e[j].to;
            if(ver==S) continue;
            if(!e[j].cap){
                printf("%d ",ver-n);
                flag=1;break;
            }
        }
        if(!flag) printf("0 ");
    }
    printf("\n");
    return 0;
}

測試點8、9、10

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <ctime>
#include <vector>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
    int x;scanf("%d",&x);return x;
}

const int MAXN=1005;
const int MAXM=305;
int n,m,v[MAXN],c[MAXM],blg[MAXN];
bool vis[MAXN];
std::vector<int> vec[MAXM],maxvec[MAXM];
struct Pair{
    int id,w;
    inline friend bool operator < (Pair A,Pair B){
        return 1.0*A.w/v[A.id]>1.0*B.w/v[B.id];
    }
}a[MAXM][MAXN];

inline int work(){
    memset(vis,0,sizeof vis);
    int ret=0;
    rin(i,1,m){
        vec[i].clear();
        int rem=c[i];
        rin(j,1,n){
            if(vis[a[i][j].id]||rem<v[a[i][j].id]) continue;
            if((rand()%(n*2))>n+vec[i].size()) continue;
            vec[i].push_back(a[i][j].id);
            vis[a[i][j].id]=1;
            rem-=v[a[i][j].id];
            ret+=a[i][j].w;
        }
    }
    return ret;
}

int main(){
    freopen("drawer10.in","r",stdin);
    freopen("drawer10.out","w",stdout);
    srand(time(0));
    n=read(),m=read();
    rin(i,1,n) v[i]=read();
    rin(i,1,m) c[i]=read();
    rin(i,1,n) rin(j,1,m) a[j][i]=(Pair){i,read()};
    rin(i,1,m) std::sort(a[i]+1,a[i]+n+1);
    int maxans=0;
    rin(k,1,10000){
        int temp=work();
        if(temp>maxans){
            memset(blg,0,sizeof blg);
            rin(i,1,m) rin(j,0,(int)vec[i].size()-1)
                blg[vec[i][j]]=i;
            maxans=temp;
        }
    }
    rin(i,1,n) printf("%d ",blg[i]);
    printf("\n");
    return 0;
}