zoukankan      html  css  js  c++  java
  • Test 6.29 T3 小学生

    问题描述

    “不错,不错!那么,准备好迎接下一道题了么?”一道白光闪过,CJK 眼前出现了 1e100 个小学生。“他们中,有一些人轨了我的机子。现在,我需要你在 1S 之内找出他们,并让他们认错!”凭借自己无所不知的神(xuan)奇(xue)力量, CJK 立刻发现了轨了 JesseLiun的机子的那 n 个小学生。但是,他还要想办法让小学生们认错。好在 CJK 有无穷多的糖,而有 p 个小学生愿意以一定的代价被收买。而小学生间有 r 个 BiShi 关系。一旦一个小学生被收买,他就会主动认错,并告发他 BiShi 的人,逼迫他们认错。那些被逼认错的人,也会告发他 BiShi 的人,以此类推。

    输入格式

    第一行两个数,n 和 p。紧接着 p 行,一行两个数 x 和 y,表示编号为 x 的小学生愿意以 y 的代价被收买。接下来一行是 m,紧跟着 m 行,每一行两个数字 x和 y,表示编号为 x 的小学生 BiShi 编号为 y 的小学生(当然,这并不意味着编号为 y 的会 BiShi 编号为 x 的)。

    输出格式

    如果 CJK 能让所有 n 个小学生认错,输出“YES”,并在下一行输出所需花费的最少糖果数。如果不能,输出“NO”,并在下一行输出编号最小的、且不会认错的小学生。

    样例输入输出

    样例输入1

    3
    2
    1 10
    2 100
    2
    1 3
    2 3

    样例输出1

    YES
    110

    样例输入2

    4
    2
    1 100
    4 200
    2
    1 2
    3 4

    样例输出2

    NO
    3

    解析

    正解是Tarjan缩环,新点的权值为环上最小值,然后再DAG动态规划。一个点如果能被其他点达到的话,就没有必要选择这个点。

    由于考场上忘了Tarjan,临时想出来一个做法,差不多就是先每个点跑一边DFS统计一个点可以由哪些点达到,然后和上面一样的逻辑,如果两个关键点可以互达说明有环,这时取最小值。否则则为能到达对方的点。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 3002
    #define M 20002
    using namespace std;
    int head[N],ver[M],nxt[M],l;
    int m,n,p,w[N],i,j,f[N],g[N],a[N];
    bool vis[N],e[N][N],key[N];
    void insert(int x,int y)
    {
    	l++;
    	ver[l]=y;
    	nxt[l]=head[x];
    	head[x]=l;
    }
    int min(int x,int y)
    {
    	if(w[x]<w[y]) return x;
    	return y;
    }
    void dfs(int x,int node)
    {
    	vis[x]=1;
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		if(!vis[y]){
    			e[node][y]=1;
    			dfs(y,node);
    		}
    	}
    }
    void dp(int x,int kid)
    {
    	if(vis[x]) return;
    	vis[x]=1;
    	if(f[x]==0) f[x]=kid;
    	else if(e[kid][f[x]]&&!e[f[x]][kid]) f[x]=kid;
    	else if(e[kid][f[x]]&&e[f[x]][kid]) f[x]=min(f[x],kid);
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		if(f[y]!=kid) dp(y,kid);
    	}
    }
    int main()
    {
    	freopen("pupil.in","r",stdin);
    	freopen("pupil.out","w",stdout);
    	cin>>n>>p;
    	for(i=1;i<=p;i++){
    		int x;
    		cin>>a[i]>>x;
    		w[a[i]]=x;
    	}
    	cin>>m;
    	for(i=1;i<=m;i++){
    		int u,v;
    		cin>>u>>v;
    		insert(u,v);
    	}
    	for(i=1;i<=n;i++) e[i][i]=1;
    	for(i=1;i<=p;i++){
    		memset(vis,0,sizeof(vis));
    		dfs(a[i],a[i]);
    	}
    	for(i=1;i<=p;i++){
    		memset(vis,0,sizeof(vis));
    		dp(a[i],a[i]);
    	}
    	int ans=0;
    	memset(vis,0,sizeof(vis));
    	for(i=1;i<=n;i++){
    		if(f[i]==0){
    			cout<<"NO"<<endl<<i<<endl;
    			return 0;
    		}
    		else if(!vis[f[i]]) ans+=w[f[i]],vis[f[i]]=1;
    	}
    	cout<<"YES"<<endl<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    

    跑的贼慢......

  • 相关阅读:
    【C语言入门教程】5.1 函数说明 与 返回值
    【C语言入门教程】4.10 综合实例
    【C语言入门教程】4.9 指向指针的指针
    【C语言入门教程】4.8 指针数组
    【C语言入门教程】4.7 指针的地址分配
    Windows 7 共享文件夹 给 VirtualBox 中的 Ubuntu 14
    【C语言入门教程】4.6 指针 和 数组
    Ubuntu 12/14 个性化配置
    【C语言入门教程】4.5 指针变量的定义与引用
    【C语言入门教程】4.4 指针 与 指针变量
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11111713.html
Copyright © 2011-2022 走看看