• BZOJ5335: [TJOI2018]智力竞赛


    BZOJ5335: [TJOI2018]智力竞赛

    https://lydsy.com/JudgeOnline/problem.php?id=5335

    分析:

    • 题意有两点需要注意:
      1. 回答过的题目还能再回答一次
      1. 图是个有向无环图(这怎么从题意中看出来?)
    • 那么就好做了,二分答案之后转化成最小路径覆盖问题。
    • 对于这类问题,我们一般的解法如下:
    • 如果不可重复经过点,那么把每个点拆成两个点对于((u,v))的一条边连((u1,v2))
    • 答案等于总点数-最大匹配数。
    • 如果可重复经过,那么用闭包传递处理出来两点的可达性再新建出这么若干条边即可转化成上面的模型。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    using namespace std;
    #define N 1050
    #define M 500050
    #define inf 0x3f3f3f3f
    const int S=N-1,T=N-2;
    int n,m,V[N],G[N][N],id[N];
    int head[N],cnt,to[M],nxt[M],flow[M];
    inline void add(int u,int v,int f) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f;
    	to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0;
    }
    void floyd() {
    	int i,j,k;
    	for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)G[i][j]|=(G[i][k]&&G[k][j]);
    }
    inline bool cmp(const int &x,const int &y) {return V[x]<V[y];}
    int Q[N],dep[N];
    bool bfs() {
    	int l=0,r=0;
    	memset(dep,0,sizeof(dep));
    	Q[r++]=S; dep[S]=1;
    	while(l<r) {
    		int x=Q[l++],i;
    		for(i=head[x];i;i=nxt[i]) if(!dep[to[i]]&&flow[i]) {
    			dep[to[i]]=dep[x]+1; if(to[i]==T)return 1; Q[r++]=to[i];
    		}
    	}return 0;
    }
    int dfs(int x,int mf) {
    	if(x==T) return mf;
    	int nf=0,i;
    	for(i=head[x];i;i=nxt[i]) if(dep[to[i]]==dep[x]+1&&flow[i]) {
    		int tmp=dfs(to[i],min(mf-nf,flow[i]));
    		if(!tmp) dep[to[i]]=0;
    		nf+=tmp;
    		flow[i]-=tmp;
    		flow[i^1]+=tmp;
    		if(nf==mf) break;
    	}return nf;
    }
    int dinic() {
    	int maxf=0,f=0;
    	while(bfs()) {
    		while((f=dfs(S,inf))) maxf+=f;
    	}return maxf;
    }
    bool check(int mid) {
    	if(mid<=n) return 1;
    	memset(head,0,sizeof(head)); cnt=1;
    	int i,j;
    	for(i=1;i<=mid;i++) {
    		add(S,i,1);
    		add(i+mid,T,1);
    	}
    	for(i=1;i<=mid;i++) for(j=1;j<=mid;j++) {
    		if(G[id[i]][id[j]]) add(i,j+mid,1);
    	}
    	return mid-dinic()<=n;
    }
    int main() {
    	scanf("%d%d",&n,&m); n++;
    	int i,k,x;
    	for(i=1;i<=m;i++) {
    		scanf("%d%d",&V[i],&k);
    		while(k--) {
    			scanf("%d",&x);
    			G[i][x]=1;
    		}
    	}
    	floyd();
    	for(i=1;i<=m;i++) id[i]=i;
    	sort(id+1,id+m+1,cmp);
    	int l=1,r=m+1;
    	while(l<r) {
    		int mid=(l+r)>>1;
    		if(check(mid)) l=mid+1;
    		else r=mid;
    	}
    	if(l==m+1) puts("AK");
    	else printf("%d
    ",V[l]);
    }
    
  • 相关阅读:
    337粘贴与选择性粘贴
    Excel VBA定制开发如何将数据重复指定次数听语音
    317、单元格的Offset
    Shape.Type属性名称及对应值列表
    Mysql解决The total number of locks exceeds the lock table size错误
    python QT5 tableview 用法1
    python qt5 菜单栏一级菜单响应单击事件
    自定义类加载器
    SpringCloudConfig与Nacos多个领域配置的不同
    多线程工具ForkJoinPool
  • 原文地址:https://www.cnblogs.com/suika/p/10230070.html
Copyright © 2020-2023  润新知