当前位置: 代码迷 >> 综合 >> 【网络流】【贪心】「九省联考 2018」秘密袭击
  详细解决方案

【网络流】【贪心】「九省联考 2018」秘密袭击

热度:78   发布时间:2023-09-27 04:04:36.0

题意:

太鬼扯了自己去看


分析:

很暴力的贪心+网络流check

这种多点共同选择的问题一定要联想到网络流

第一问每次在残留网络上跑看能不能跑出新流量,能跑出即为当前层数。

第二问用二分,每次重建图跑就好了,不用非要去存图,太耗内存而且代码复杂度也差不多。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 510
#define INF 0x3FFFFFFF
using namespace std;
vector<int> a[MAXN],w[MAXN],rev[MAXN];
int s,t,tot;
void add_edge(int u,int v,int val){
    a[u].push_back(v);a[v].push_back(u);w[u].push_back(val);w[v].push_back(0);rev[u].push_back(a[v].size()-1);rev[v].push_back(a[u].size()-1);
}
int T,C,n,m;
int b[MAXN],S[MAXN],ans[MAXN];
vector<int> tar[MAXN][MAXN];
void build_edge(int x,int y){
    for(int i=0;i<int(tar[x][y].size());i++)add_edge(x,tar[x][y][i]+n,1);
}
void dele_edge(int x,int y){
    for(int i=0;i<int(tar[x][y].size());i++){
    a[tar[x][y][i]+n].pop_back();w[tar[x][y][i]+n].pop_back();rev[tar[x][y][i]+n].pop_back();}int sd=int(tar[x][y].size());for(int i=1;i<=sd;i++)a[x].pop_back(),w[x].pop_back(),rev[x].pop_back();
}
void clear_it(int x,int i){
    w[x][i]=w[a[x][i]][rev[x][i]]+w[x][i];w[a[x][i]][rev[x][i]]=0;	
}
void clear_edge(){
    for(int i=0;i<tot;i++)for(int j=0;j<int(a[i].size());j++)if(a[i][j]>i)clear_it(i,j);
}
int d[MAXN],g[MAXN];
int dfs(int x,int f){
    if(x==t)return f;int less=f;for(int i=0;i<int(a[x].size())&&less;i++)if(w[x][i]&&d[a[x][i]]==d[x]-1){
    int res=dfs(a[x][i],min(less,w[x][i]));less-=res;w[x][i]-=res;w[a[x][i]][rev[x][i]]+=res;if(d[s]>tot)return f-less;}if(less==0)return f;g[d[x]]--;if(g[d[x]]==0){
    d[s]=tot+1;return f-less;	}d[x]=tot+1;for(int i=0;i<int(a[x].size());i++)if(w[x][i])d[x]=min(d[x],d[a[x][i]]);d[x]++;g[d[x]]++;return f-less;
}
int maxf(){
    g[0]=tot;memset(d,0,sizeof d);int res=0;while(d[s]<=tot)res+=dfs(s,INF);	
// clear_edge();return res;
}
bool check(int x,int len){
    int sum=1;clear_edge();for(int i=1;i<len;i++) {
    build_edge(i,ans[i]);sum+=(ans[i]!=(m+1));}for(int i=1;i<=S[x];i++) build_edge(x,i);int res=maxf();for(int i=S[x];i>=1;i--) dele_edge(x,i);for(int i=len-1;i>=1;i--) dele_edge(i,ans[i]);return res==sum;
}
int b_search(int x){
    if(ans[x]<=S[x])return 0;int l=1,r=x-1,res=x;while(l<=r){
    int mid=(l+r)>>1;if(check(x,mid)){
    res=x-mid;l=mid+1;}elser=mid-1;	}return res;
}
void Print_edges(){
    PF("-------------\nPrint edges:\n");for(int i=0;i<tot;i++){
    PF("%d:\n",i);for(int j=0;j<int(a[i].size());j++)PF("{%d %d}",a[i][j],w[i][j]);PF("\n");}PF("Print finished!\n---------------\n");
}	
int main(){
    SF("%d%d",&T,&C);int x;while(T--){
    SF("%d%d",&n,&m);s=0;t=n+m+1;tot=t+1;for(int i=1;i<=m;i++){
    SF("%d",&b[i]);add_edge(i+n,t,b[i]);}for(int i=1;i<=n;i++){
    for(int j=1;j<=m+1;j++)tar[i][j].clear();for(int j=1;j<=m;j++){
    SF("%d",&x);if(x) tar[i][x].push_back(j);}}for(int i=1;i<=n;i++){
    SF("%d",&S[i]);ans[i]=m+1;add_edge(s,i,1);}for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
    build_edge(i,j);if(maxf()==1){
    ans[i]=j;break;}dele_edge(i,j);}}for(int i=1;i<=n;i++)PF("%d ",ans[i]);PF("\n");for(int i=n;i>=1;i--)dele_edge(i,ans[i]);for(int i=1;i<=n;i++)PF("%d ",b_search(i));	PF("\n");for(int i=0;i<tot;i++)a[i].clear(),w[i].clear(),rev[i].clear();}
}
  相关解决方案