[专题总结]最大权闭合子图和上下界网络流基础
一页板子题。里面也有难的。但是建图不是特别复杂,*听到NC喊标签然后就AC了。
植物大战僵尸:
最大权闭合子图,挺板子的。
考虑一下每个植物都会保护它身后的植物,然后成环的保护关系一个都不能吃。
然后就是板子。
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 using namespace std; 5 #define S 3333333 6 vector<int>v[999]; 7 int n,m,val[999],ord[33][33],pc,Fir[999],L[S],To[S],deg[999],q[S],Ec,tp[999]; 8 int ec=1,fir[999],l[S],to[S],w[S],E,d[999],ans; 9 bool bfs(){ 10 for(int i=1;i<=E;++i)d[i]=0; 11 for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(w[i]&&!d[to[i]]) 12 d[q[++t]=to[i]]=d[q[h]]+1; 13 return d[E]; 14 } 15 int dfs(int p,int flow){int r=flow; 16 if(p==E)return flow; 17 for(int i=fir[p];i&&r;i=l[i])if(d[to[i]]==d[p]+1&&w[i]){ 18 int x=dfs(to[i],min(w[i],r)); 19 if(!x)d[to[i]]=0; 20 w[i]-=x;w[i^1]+=x;r-=x; 21 }return flow-r; 22 } 23 void Link(int a,int b){L[++Ec]=Fir[a];Fir[a]=Ec;To[Ec]=b;deg[b]++;} 24 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;w[ec]=V;} 25 void con(int a,int b,int V){link(a,b,V);link(b,a,0);} 26 int main(){ 27 scanf("%d%d",&n,&m); 28 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)ord[i][j]=++pc;E=++pc; 29 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){ 30 int N,x,y;scanf("%d%d",&val[ord[i][j]],&N); 31 for(int p=1;p<=N;++p)scanf("%d%d",&x,&y),v[ord[i][j]].push_back(ord[x+1][y+1]); 32 if(j^1)v[ord[i][j]].push_back(ord[i][j-1]); 33 } 34 for(int i=1;i<pc;++i)for(int j=0;j<v[i].size();++j)Link(i,v[i][j]); 35 int t=1; 36 for(int i=1;i<pc;++i)if(!deg[i])q[++t]=i; 37 for(int h=2;h<=t;tp[q[h]]=1,++h)for(int i=Fir[q[h]];i;i=L[i]){ 38 deg[To[i]]--;if(!deg[To[i]])q[++t]=To[i]; 39 } 40 for(int i=1;i<pc;++i)if(tp[i]){ 41 if(val[i]>0)con(0,i,val[i]),ans+=val[i];else con(i,E,-val[i]); 42 for(int j=0;j<v[i].size();++j)if(tp[v[i][j]])con(v[i][j],i,S); 43 } 44 while(bfs())ans-=dfs(0,S);printf("%d ",ans); 45 }
寿司餐厅
(颓标签之后)最大神的一个?
一定要好好看题啊不然想到暴毙也想不出来。
同一种寿司吃多次只会付出一次代价!!!(是同一种,不是同一个代号)
不然没法做。
现在就是对于每个区间只会获得一次收益,对于每种寿司只会付出一次代价,对于同一个代号的寿司只会付出一次代价。
比较明显的是,
1,如果你吃了区间[l,r]那么你一定也吃了[l,r-1]与[l+1,r]。就是区间的包含关系。
这种关系有传递性,在最大权闭合子图里不必考虑别的了。
2,然后如果你吃了[l,l]那么你就是吃了这种寿司,不管吃了几次都付出$a_i$代价。
3,如果你吃了x这种寿司,那么就表示你一定吃过代号为$a_x$的寿司,不管吃了几种几个都付出$a_x^2 imes m$代价
根据上面这3种关系建边就可以满足题意。
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 #define S 6666666 5 int fir[S],l[S],to[S],v[S],cur[S],ec=1,pc,o[111][111],a[111],n,m,d[S],q[S],E,O[1111],ans; 6 bool bfs(){ 7 for(int i=0;i<=pc;++i)cur[i]=fir[i],d[i]=0;d[0]=1; 8 for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&!d[to[i]]) 9 d[q[++t]=to[i]]=d[q[h]]+1; 10 return d[E]; 11 } 12 int dfs(int p,int flow){int r=flow; 13 if(p==E)return r; 14 for(int i=cur[p];i&&r;i=l[i])if(v[i]&&d[to[i]]==d[p]+1){ 15 cur[p]=i;int x=dfs(to[i],min(r,v[i])); 16 if(!x)d[to[i]]=0; 17 v[i]-=x;v[i^1]+=x;r-=x; 18 }return flow-r; 19 } 20 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;} 21 void con(int a,int b,int V=S){link(a,b,V);link(b,a,0);} 22 void add(int a,int V){if(V>0)con(0,a,V),ans+=V;else con(a,E,-V);} 23 int main(){ 24 scanf("%d%d",&n,&m); 25 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 26 for(int i=1;i<=n;++i)if(!O[a[i]])O[a[i]]=++pc; 27 for(int i=1;i<=n;++i)for(int j=i;j<=n;++j)o[i][j]=++pc; 28 for(int i=1;i<=n;++i)con(o[i][i],O[a[i]]); 29 E=++pc; 30 for(int i=1;i<=1000;++i)if(O[i])add(O[i],-i*i*m); 31 for(int i=1,x;i<=n;++i){ 32 scanf("%d",&x);x-=a[i];add(o[i][i],x); 33 for(int j=i+1;j<=n;++j)scanf("%d",&x),add(o[i][j],x),con(o[i][j],o[i+1][j]),con(o[i][j],o[i][j-1]); 34 } 35 while(bfs())ans-=dfs(0,S);printf("%d ",ans); 36 }