1. 程式人生 > 其它 >QZHWTEST2021.5.23分析

QZHWTEST2021.5.23分析

樹上游戲

題面

題目描述

\(FLY\)和朋友玩一個遊戲。
在一棵樹上,每個點都有一個點權,\(FLY\)和朋友從根開始,輪流取出點權作為分值,並且由當前玩家選擇前往哪一個兒子,直到到達葉子節點後計算總分,總分大的勝。
\(FLY\)和他的朋友都非常謹慎,能夠每次選擇兒子都做到理論上的最優值,請你判斷遊戲是否有先手必勝的策略。

輸入

第一行輸入資料組數\(T\)
第二行輸入樹的點數\(n\)
第三行\(n\)個數字,為每個點的點權
接下來\(n-1\)行輸入樹邊\(u\),\(v\)

輸出

若先手必勝,則輸出\(win\)
若先手必敗,則輸出\(loss\)
若必定平局,則輸出\(draw\)

樣例輸入

2
5
3 4 2 3 2
1 2
2 3
2 4
4 5
5
4 1 4 3 3
1 2
2 3
3 4
4 5

樣例輸出

draw
win

思路

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100005
using namespace std;
int t,n,ans;//ans=0表示輸,1表示平,2表示勝 
int a[maxn],uu,vv;
int head[maxn],w=0;
struct gragh{
	int to,nex;
}g[maxn*2];
int tot[2];//0先手,1後手 
void clear(){
	w=0;ans=-1;
	memset(a,0,sizeof(a));
	memset(g,0,sizeof(g));
	memset(tot,0,sizeof(tot));
	memset(head,0,sizeof(head));
}
void add(int x,int y){
	g[++w].to=y;
	g[w].nex=head[x];
	head[x]=w;
}
int dfs(int i,int fa,bool flag){
	int anss=-1;
	bool flag2=0;
	tot[flag]+=a[i];
	for(int j=head[i];j!=0;j=g[j].nex){
		if(g[j].to==fa){
			continue;
		}
		flag2=1;
		int x=dfs(g[j].to,i,!flag);
		if(!flag){//FLY
			anss=(anss==-1?x:max(x,anss));
		}else{
			anss=(anss==-1?x:min(x,anss));
		}
	}
	if(!flag2){//葉子 
		if(tot[0]>tot[1]){
			anss=2;
		}else if(tot[0]==tot[1]){
			anss=1;
		}else{
			anss=0;
		}
	} 
	tot[flag]-=a[i];
	return anss;
}
int main(){
	scanf("%d",&t);
	while(t--){
		clear();
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		for(int i=1;i<n;i++){
			scanf("%d%d",&uu,&vv);
			add(uu,vv);
			add(vv,uu);
		}
		ans=dfs(1,-1,0);
		if(ans==0){
			printf("loss\n");
		}else if(ans==1){
			printf("draw\n");
		}else{
			printf("win\n");
		}
	}
	return 0;
}

無線通訊網 & 洛谷P1991

題面

題目描述

國防部計劃用無線網路連線若干個邊防哨所。\(2\)種不同的通訊技術用來搭建無線網路;
每個邊防哨所都要配備無線電收發器;有一些哨所還可以增配衛星電話。
任意兩個配備了一條衛星電話線路的哨所(兩邊都有衛星電話)均可以通話,無論他們相距多遠。而只通過無線電收發器通話的哨所之間的距離不能超過\(D\),這是受收發器的功率限制。收發器的功率越高,通話距離\(D\)會更遠,但同時價格也會更貴。
收發器需要統一購買和安裝,所以全部哨所只能選擇安裝一種型號的收發器。換句話說,每一對哨所之間的通話距離都是同一個\(D\)。你的任務是確定收發器必須的最小通話距離\(D\)

,使得每一對哨所之間至少有一條通話路徑(直接的或者間接的)。

輸入

\(1\)行:\(2\)個整數\(S\)\(1\le S\le 100\))和\(P\)\(S<P\le 500\)),\(S\)表示可安裝的衛星電話的哨所數,\(P\)表示邊防哨所的數量。
接下里\(P\)行,每行描述一個哨所的平面座標(\(x\),\(y\)),以\(km\)為單位,整數,\(0\le x\),\(y\le 10000\)

輸出

\(1\)個實數\(D\),表示無線電收發器的最小傳輸距離。精確到小數點後兩位。

樣例輸入

2 4
0 100
0 300
0 600
150 750

樣例輸出

212.13

思路

程式碼

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxp 505 
using namespace std;
int s,p;
struct node{
	int x,y;
}a[maxp];
int w=0;
struct line{
	int x,y;
	double len;
}l[maxp*maxp];
double dis(int p1,int p2){
	return sqrt(pow(a[p1].x-a[p2].x,2)+pow(a[p1].y-a[p2].y,2));
}
bool cmp(line a,line b){
	return a.len<b.len;
}
int f[maxp];
int find(int x){
	if(f[x]==x){
		return x;
	}
	return f[x]=find(f[x]);
}
int main(){
	scanf("%d%d",&s,&p);
	for(int i=1;i<=p;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
		f[i]=i;
	}
	for(int i=1;i<=p;i++){
		for(int j=1;j<i;j++){
			l[++w].x=i;
			l[w].y=j;
			l[w].len=dis(i,j);
		}
	}
	sort(l+1,l+1+w,cmp);
	int tot=0;
	double ans=-1;
	for(int i=1;i<=w;i++){
		int r1=find(l[i].x),r2=find(l[i].y);
		if(r1!=r2){
			f[r2]=r1;
			tot++;
			ans=l[i].len;
		} 
		if(tot==p-s){
			printf("%.2f",ans);
			return 0;
		}
	}
	return 0;
}
/*
2 4
0 100
0 300
0 600
150 750
*/

仙人掌 & 洛谷P3687

題面

題目描述

如果一個無自環無重邊無向連通圖的任意一條邊最多屬於一個簡單環,我們就稱之為仙人掌。所謂簡單環即不經過重複的結點的環。
現在九條可憐手上有一張無自環無重邊的無向連通圖,但是她覺得這張圖中的邊數太少了,所以她想要在圖上連上一些新的邊。同時為了方便的儲存這張無向圖,圖中的邊數又不能太多。
經過權衡,她想要加邊後得到的圖為一棵仙人掌。
不難發現合法的加邊方案有很多,可憐想要知道總共有多少不同的加邊方案。
兩個加邊方案是不同的當且僅當一個方案中存在一條另一個方案中沒有的邊。

輸入

多組資料,第一行輸入一個整數\(T\)表示資料組數。
每組資料第一行輸入兩個整數\(n\),\(m\),表示圖中的點數與邊數。
接下來\(m\)行,每行兩個整數\(u\),\(v\)(\(1\le u\),\(v\le n\),\(u\ne v\)) 表示圖中的一條邊。保證輸入的圖聯通且沒有自環與重邊。

輸出

對於每組資料,輸出一個整數表示方案數,當然方案數可能很大,請對\(998244353\)取模後輸出。

樣例輸入

2
3 2
1 2
1 3
5 4
1 2
2 3
2 4
1 5

樣例輸出

2
8

思路

程式碼