树上游戏

题面

题目描述

\(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

思路

看到题目,直接打爆搜,回溯时优化成树形\(DP\),复杂度\(O(NT)\)。

在搜索时,记录当前节点的深度\(depth\),这可以帮助我们知道现在轮到谁了。我用的是\(flag\)记录,对应意思代码中有。

每个节点搜索每一个孩子,一直搜到叶子。到叶子后,判断此时先后手谁分多,回溯到上一个节点,最后输出结果即可。

但是你会发现,样例的第一组都过不去。原因是这样的:



由图,在节点\(2\)时,如果向\(3\)走,先手胜;如果向\(4\)走,平局。因为此时是后手选,根据最优策略,故他一定会选\(4\)。因此,我们要在每次回溯时判断是谁选择,先手应取尽量好的,后手应取对后手尽量好的。

代码

#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

思路

题目中说到“直接或者间接连通”与“求最小通话距离”,这很容易让我们想到最小生成树。枚举每两个点,计算出距离\(dis\),然后排序,建立最小生成树,输出最大边即可。

需注意的是,题中有给到 卫星电话 这个东西,可以任两点无条件直接连通。考虑到最小生成树要连接\(n-1\)条边,而 卫星电话 可以随便连\(s-1\)条边,故我们只需要枚举最小的\(n-s\)(即\(n-1-(s-1)\))条边即可,剩下的\(s-1\)条较长的边用 卫星电话 即可。

代码

#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

思路

代码

最新文章

  1. 使用JQuery统计input和textarea文字输入数量代码
  2. shell判断条件整理
  3. Leetcode: Surrounded regions
  4. 其他信息: 未找到源,不过,未能搜索部分或所有事件日志。 若要创建源,您需要用于读取所有事件日志的权限以确保新的源名称是唯一的。 不可访问的日志: Security。
  5. Redis从基础命令到实战之有序集合类型(SortedSet)
  6. Majority Element || leetcode
  7. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)
  8. [转载]关于CSDN, cnblog, iteye和51cto四个博客网站的比较与分析
  9. Oracle中decode方法的作用
  10. CenOS7.1安装VNC——让win7远程桌面linux
  11. make[1]: *** [/workopenwrt/trunk/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/stamp/.tools_install_nnnnn] Error 2 make[1]: Leaving directory `/work/openwrt/trunk&#39; make: *** [world]
  12. jQuery的拾色器
  13. POLARDB &#183; 最佳实践 &#183; POLARDB不得不知道的秘密(二)
  14. 8ci
  15. OneProxy 管理
  16. python中字典内置方法
  17. C# 创建精简版IIS
  18. java集合类——Stack栈类与Queue队列
  19. Django之MTV
  20. IIS服务器部署

热门文章

  1. Redis:redis.conf配置文件 - 及配置详解
  2. Shell脚本对Linux进行文件校验
  3. Android Binder 进程间通讯机制梳理
  4. 【译】.NET 对象分配工具
  5. python之数据驱动Txt操作
  6. 达梦数据库(DM8)大规模并行集群MPP 2节点安装部署
  7. MYSQL一个设备上的主从复制实现-windows
  8. mac上安装brew----笔记
  9. 第十七篇 -- QTreeWidget与QDockWidget
  10. windows下python -m pip install --upgrade pip升级后报错的解决方法