zoukankan      html  css  js  c++  java
  • 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]);
    }
    
  • 相关阅读:
    spring(2)
    Android之滑动按钮实现Demo
    spring(1)
    spring(4)
    Android之ImageSwitch控件
    使用非阻塞ServerSocketChannel、SocketChannel代替ServerSocket和Socket
    Android之界面刷新(invalidate和postInvalidate使用)
    Android之改变控件的背景及形态
    Android之获得内存剩余大小与总大小
    OpenCV中矩阵的归一化
  • 原文地址:https://www.cnblogs.com/suika/p/10230070.html
Copyright © 2011-2022 走看看