P9954 [USACO20OPEN] Cowntact Tracing B

洛谷

首先观察数据范围,发现 \(N\)\(T\) 都很小,那么就可以直接枚举计算答案了。

将几次握手按照时间排序,首先枚举零号病人是哪一只奶牛,再枚举 \(K\) 的值。

如果你把状态设置为 \(0\) 表示没有感染,其他数字表示可以传染的人数,那么需要特别判断一下 \(K\)\(0\) 的情况。

注意每次握手都要将这只奶牛的可传染次数减一。

枚举完成后进行模拟,统计可以作为零号病人的有那几只奶牛,再取 \(K\) 的最小值和最大值即可。

如何判断有无上限?

如果 \(T\) 次可行,那么每一次握手都必定传染,那么加上几次都必定可行,所以若最大值为 \(T\) 时,无上界。

模拟用时 \(O(T+N)\)

代码用时 \(O(NT(N+T))\)

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,t,vis[10005],f[10005],ans,ans2=1e9,ans3,to[10005];
struct P{
	int t,x,y;
}a[3005];
bool cmp(P a,P b){
	return a.t<b.t;
}
signed main(){
    cin>>n>>t;
    char c;
    for(int i=1;i<=n;i++){
    	cin>>c;
    	vis[i]=c-48;
	}
	for(int i=1;i<=t;i++){
		cin>>a[i].t>>a[i].x>>a[i].y; 
	}
	sort(a+1,a+t+1,cmp);
	for(int i=1;i<=n;i++){
		memset(f,0,sizeof(f));
		f[i]=1;
		bool fl=false;
		for(int k=1;k<=n;k++){
			if(f[k]&&!vis[k]||!f[k]&&vis[k]){
				fl=true;
				break;
			}
		}
		if(!fl){
			if(!to[i]){
				to[i]=1;
				ans++;
			}
			ans2=min(ans2,0ll);
			ans3=max(ans3,0ll);
		}
		for(int j=1;j<=t;j++){
			memset(f,0,sizeof(f));
			f[i]=j;
			for(int k=1;k<=t;k++){
				int x=f[a[k].x],y=f[a[k].y];
				if(x>0){
					f[a[k].x]--;
					if(!f[a[k].x])f[a[k].x]=-1;
					if(y==0)f[a[k].y]=j;
				}
				if(y>0){
					f[a[k].y]--;
					if(!f[a[k].y])f[a[k].y]=-1;
					if(x==0)f[a[k].x]=j;
				}
			}
			bool fl=false;
			for(int k=1;k<=n;k++){
				if(f[k]&&!vis[k]||!f[k]&&vis[k]){
					fl=true;
					break;
				}
			}
			if(!fl){
				if(!to[i]){
					to[i]=1;
					ans++;
				}
				ans2=min(ans2,j);
				ans3=max(ans3,j);
			}
		}
	}
	cout<<ans<<' '<<ans2;
	if(ans3!=t)cout<<' '<<ans3;
	else cout<<' '<<"Infinity";
    return 0;
}
posted @ 2025-10-31 09:00  huhangqi  阅读(14)  评论(0)    收藏  举报
/*
*/