[LOJ2288][THUWC2017]大蔥的神力:搜尋+揹包DP+費用流+隨機化
阿新 • • 發佈:2018-12-27
分析
測試點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;
}