动态加边
做tsinsen发现题解都舔不懂QAQ,只能学习一个
- bzoj1070修车
吃了hzwer的安利,是为下一道题做铺垫
n辆车,m个修车工,把修车工拆成n个,每辆车分别向n*m个修车工连边,第i辆车向第(j-1)*n+k个修车工连的边边权为t[i][j]*k,代表第j个修车工修的倒数第k辆车为i
这样建边的意义在于,修车工修倒数第k辆车只会对他修的倒数第k辆车及这辆车以后的车的等待时间产生影响,影响恰为t[i][j]*k
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define inf 0x3f3f3f3f 5 #define maxn 605 6 #define maxm 33005 7 int cnt,v[maxm<<1],w[maxm<<1],c[maxm<<1],next[maxm<<1],first[maxn]; 8 int n,m,SSS,TTT,cost,dist[maxn],q[maxn],vis[maxn],tim[65][15]; 9 10 void add(int st,int end,int val,int cst){ 11 v[cnt]=end;w[cnt]=val;c[cnt]=cst;next[cnt]=first[st];first[st]=cnt++; 12 v[cnt]=st;w[cnt]=0;c[cnt]=-cst;next[cnt]=first[end];first[end]=cnt++; 13 } 14 bool spfa(){ 15 int head=0,tail=0; 16 memset(dist,0x3f,sizeof(dist)); 17 memset(vis,0,sizeof(vis)); 18 q[tail++]=SSS; 19 vis[SSS]=1; 20 dist[SSS]=0; 21 int nn=TTT+1; 22 while(head!=tail){ 23 int x=q[head]; 24 if(++head==nn)head=0; 25 vis[x]=0; 26 for(int e=first[x];e!=-1;e=next[e]) 27 if(w[e]&&dist[v[e]]>dist[x]+c[e]){ 28 dist[v[e]]=dist[x]+c[e]; 29 if(!vis[v[e]]){ 30 vis[v[e]]=1; 31 q[tail]=v[e]; 32 if(++tail==nn)tail=0; 33 } 34 } 35 } 36 return dist[TTT]!=inf; 37 } 38 int dfs(int x,int lim){ 39 if(x==TTT)return lim; 40 int lim1=lim; 41 for(int e=first[x];e!=-1;e=next[e]){ 42 if(!vis[v[e]]&&w[e]&&dist[v[e]]==dist[x]+c[e]){ 43 vis[v[e]]=1; 44 int flow=dfs(v[e],min(lim,w[e])); 45 w[e]-=flow;w[e^1]+=flow; 46 cost+=c[e]*flow; 47 if((lim-=flow)<=0)break; 48 } 49 } 50 if(lim==lim1)dist[x]=inf; 51 return lim1-lim; 52 } 53 int main(){ 54 memset(first,-1,sizeof(first)); 55 scanf("%d%d",&m,&n);//n cars, m people 56 int tot=n*m; 57 SSS=0,TTT=tot+n+1; 58 for(int i=1;i<=n;i++) 59 for(int j=1;j<=m;j++) 60 scanf("%d",&tim[i][j]); 61 for(int i=1;i<=n;i++){ 62 add(SSS,tot+i,1,0); 63 for(int j=1;j<=m;j++) 64 for(int k=1;k<=n;k++) 65 add(i+tot,(j-1)*n+k,1,tim[i][j]*(n-k+1)); 66 } 67 for(int i=1;i<=m;i++) 68 for(int j=1;j<=n;j++) 69 add((i-1)*n+j,TTT,1,0); 70 while(spfa()){ 71 memset(vis,0,sizeof(vis)); 72 vis[SSS]=1; 73 dfs(SSS,inf); 74 } 75 printf("%.2lf\n",(double)cost/n);// 76 return 0; 77 } 78
- bzoj2879美食节
数据范围大得飞起来
于是要先连一部分边,然后在每一次增广之后为增广的节点加边,使得在下一次增时保证所有厨师都在备选方案中
通过这道题也发现之前写的重口味都是萎的,于是立下了以后再写重口味就cisi的flag
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define inf 0x3f3f3f3f 5 #define maxn 100005 6 #define maxm 3000005 7 int cnt,u[maxm<<1],v[maxm<<1],w[maxm<<1],c[maxm<<1],Next[maxm<<1],first[maxn]; 8 int ans,SSS,TTT,tot,haha,n,m,dist[maxn],q[maxn],p[45],pre[maxn],t[45][105],vis[maxn]; 9 void add(int st,int end,int val,int cst){ 10 u[cnt]=st;v[cnt]=end;w[cnt]=val;c[cnt]=cst;Next[cnt]=first[st];first[st]=cnt++; 11 u[cnt]=end;v[cnt]=st;w[cnt]=0;c[cnt]=-cst;Next[cnt]=first[end];first[end]=cnt++; 12 } 13 bool spfa(){ 14 int head=0,tail=0; 15 memset(dist,0x3f,sizeof(dist)); 16 memset(vis,0,sizeof(vis)); 17 q[tail++]=SSS; 18 dist[SSS]=0,vis[SSS]=1; 19 while(head!=tail){ 20 int x=q[head]; 21 if(++head==maxn)head=0; 22 vis[x]=0; 23 for(int e=first[x];e!=-1;e=Next[e]) 24 if(w[e]&&dist[v[e]]>dist[x]+c[e]){ 25 dist[v[e]]=dist[x]+c[e]; 26 pre[v[e]]=e; 27 if(!vis[v[e]]){ 28 vis[v[e]]=1; 29 q[tail]=v[e]; 30 if(++tail==maxn)tail=0; 31 } 32 } 33 34 } 35 return dist[TTT]!=inf; 36 } 37 void mcf(){ 38 int x=TTT,flow=inf; 39 while(x!=SSS){ 40 flow=min(flow,w[pre[x]]); 41 x=u[pre[x]]; 42 } 43 x=TTT; 44 while(x!=SSS){ 45 ans+=flow*c[pre[x]]; 46 w[pre[x]]-=flow;w[pre[x]^1]+=flow; 47 x=u[pre[x]]; 48 } 49 int num=u[pre[TTT]],a=(num-1)/tot+1,b=num%tot+1; 50 add((a-1)*tot+b,TTT,1,0); 51 for(int i=1;i<=n;i++) 52 add(haha+i,(a-1)*tot+b,1,t[i][a]*b); 53 } 54 int main(){ 55 memset(first,-1,sizeof(first)); 56 scanf("%d%d",&n,&m); 57 SSS=0,TTT=maxn-1; 58 for(int i=1;i<=n;i++){ 59 scanf("%d",&p[i]); 60 tot+=p[i]; 61 } 62 haha=tot*m; 63 for(int i=1;i<=n;i++) 64 add(SSS,haha+i,p[i],0); 65 for(int i=1;i<=n;i++) 66 for(int j=1;j<=m;j++){ 67 scanf("%d",&t[i][j]); 68 add(haha+i,(j-1)*tot+1,1,t[i][j]); 69 } 70 for(int i=1;i<=m;i++) 71 add((i-1)*tot+1,TTT,1,0); 72 while(spfa())mcf(); 73 printf("%d\n",ans); 74 return 0; 75 } 76