【POJ3686】The Windy's
阿新 • • 發佈:2021-07-30
題目
解析:
這道題建模挺妙的,難點在於如何處理累積時間。
首先對於一個車間,如果加工了\(k\)個玩具,那麼總時間為
由此我們發現,每一個玩具可以提出來單獨算。將每個車間拆成\(n\)個點,第\(i\)個點表示倒數第\(i\)個生產出來的玩具。每個玩具\(j\)分別向\(i\)連一條容量為\(1\),費用為\(i*time[i][j]\)的邊。建完圖後跑費用流即可。
code:
#include <iostream> #include <algorithm> #include <cstdio> #include <queue> using namespace std; const int Maxn=2555; const int Maxm=127555; const int inf=1e9; int T,n,m,size,s,t,sum; int first[Maxn],dis[Maxn],tmp[Maxn],vis[Maxn],f[55][55]; struct shu{int to,next,l,c;}e[Maxm<<1]; inline void add(int x,int y,int l,int c) { e[++size].next=first[x],first[x]=size,e[size].to=y,e[size].l=l,e[size].c=c; } inline int min(int x,int y){return x>y ? y : x;} inline void init() { scanf("%d%d",&n,&m); t=n*m+n+1,size=-1,sum=0; for(int i=s;i<=t;i++) first[i]=-1; for(int i=1;i<=n;i++) { add(s,i,1,0),add(i,s,0,0); for(int j=1;j<=m;j++) { scanf("%d",&f[i][j]); add(j*n+i,t,1,0),add(t,j*n+i,0,0); } } for(int i=1;i<=n;i++) for(int k=1;k<=m;k++) for(int j=1;j<=n;j++) add(i,k*n+j,1,j*f[i][k]),add(k*n+j,i,0,-j*f[i][k]); } inline bool spfa() { queue<int>q; for(int i=s;i<=t;i++) dis[i]=inf,tmp[i]=first[i]; q.push(s),dis[s]=0,vis[s]=1; while(!q.empty()) { int p=q.front();q.pop(),vis[p]=0; for(register int u=first[p];~u;u=e[u].next) { int to=e[u].to; if(!e[u].l || dis[to]<=dis[p]+e[u].c) continue; dis[to]=dis[p]+e[u].c; if(!vis[to]) vis[to]=1,q.push(to); } } return dis[t]!=inf; } inline int dfs(int p,int flow) { if(p==t) return flow; int s=0;vis[p]=1; for(register int &u=tmp[p];~u;u=e[u].next) { int to=e[u].to; if(!e[u].l || dis[to]!=dis[p]+e[u].c || vis[to]) continue; int minn=dfs(to,min(flow-s,e[u].l)); e[u].l-=minn,e[u^1].l+=minn,s+=minn,sum+=minn*e[u].c; if(s==flow) break; } vis[p]=0; return s; } inline void solve() { while(spfa()){while(dfs(s,inf));} printf("%.6f\n",(double)sum/n); } int main() { scanf("%d",&T); while(T--) { init(); solve(); } return 0; }