USACO——Closing the farm

本文介绍了USACO 2016 Silver Problem 3,该问题涉及农场的关闭策略。FJ计划逐个关闭谷仓以节省成本,并想知道在每次关闭后农场是否仍保持全连通状态。输入包括谷仓数量、道路数量、道路连接信息和关闭顺序,输出为每次关闭后的连通性状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目背景

USACO 2016 US Open Contest, Silver
Problem 3

题目描述

FJ 和他的奶牛们正在计划离开小镇做一次长的旅行,同时 FJ 想临时地关掉他的农场以节省一些金钱。

这个农场一共有被用 M 条双向道路连接的 N 个谷仓(1≤N,M≤3000)。为了关闭整个农场,FJ 计划每一次关闭掉一个谷仓。当一个谷仓被关闭了,所有的连接到这个谷仓的道路都会被关闭,而且再也不能够被使用。

FJ 现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭谷仓之后的时间)时他的农场是否是“全连通的”——也就是说从任意的一个开着的谷仓开始,能够到达另外的一个谷仓。注意自从某一个时间之后,可能整个农场都开始不会是“全连通的”。

输入格式

输入的第一行是两个整数 N 和 M ;
下面的 M 行每行都描述了一条连接两个谷仓的双向路径的两个端点(输入的点保证在 1...N 的范围内);
最后的 N 行是一个 1...N 的排列,描述每一个谷仓被关闭的顺序。

输出格式

输出一共有 N 行,每行可以是“YES”或者“NO”。
第一行表示一开始时整个农场是否是“全连通的”;
然后第 i+1 行表示在第 i 次的关闭谷仓之后整个农场是否是“全连通的”。

样例数据 1

输入

4 3 
1 2 
2 3 
3 4 



2

输出

YES 
NO 
YES 
YES

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
	int to[3001];
	int time;
	bool close;
}edge[3010];
int n,m,count;
int close[3010];
bool going[3010];
inline int readint()
{
    int i=0,f=1;
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0' && ch<='9';ch=getchar())
        i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}
inline int add(int x,int y)
{
	++edge[x].time;
	edge[x].to[edge[x].time]=y;
}
inline void go(int begin)
{
	going[begin]=true;
	++count;
	for(int i=1;i<=edge[begin].time;++i)
	if(!going[edge[begin].to[i]]&&!edge[edge[begin].to[i]].close) go(edge[begin].to[i]);
}
int main()
{
	int x,y;
	n=readint();
	m=readint();
	for(int i=1;i<=m;++i)
	{
		x=readint();
		y=readint();
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;++i) close[i]=readint();
	int k=0;
	do
	{
		count=0;
		edge[close[k]].close=true;
		for(int i=1;i<=n;++i) if(!edge[i].close)
		{
			memset(going,false,sizeof(going));
			go(i);
			break;
		}
		if(count==(n-k)) puts("YES");
		else puts("NO");
		++k;
	}while(close[k+1]);
	return 0;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
struct hh{int u,v,next;
}ma[1000000];
int nb=0,father[500000],d[500000],x,y,nu[500000],first[500000],n,m;
bool check1[500000],check2[500000];
void crea(int u,int v)
{
	ma[++nb].next=first[u];
	ma[nb].u=u;
	ma[nb].v=v;
	first[u]=nb;
}
int ffa(int x)
{
	if(father[x]!=x)
	  return father[x]=ffa(father[x]);
	return x;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	memset(first,0,sizeof(first));
	memset(check1,false,sizeof(check1));
	memset(check2,false,sizeof(check2));
	for(int i=1;i<=m;++i)
	{
		cin>>x>>y;
		crea(x,y);
		crea(y,x);
	}
	for(int i=n;i>0;i--)
	{
		cin>>d[i];
		father[i]=i;
		nu[i]=1;
	}
	for(int i=1;i<=n;++i)
	{
		x=ffa(d[i]);
		check2[d[i]]=true;
		for(int j=first[d[i]];j>0;j=ma[j].next)
		{
			if(!check2[ma[j].v])
			  continue;
			y=ffa(ma[j].v);
			if(x!=y)
			{
				father[y]=x;
				nu[x]+=nu[y];
			}
		}
		if(nu[x]==i)
		{
			check1[n-i+1]=true;
		}
	}
	for(int i=1;i<=n;++i)
	  if(check1[i])
	    cout<<"YES"<<endl;
	  else
	    cout<<"NO"<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值