您的位置:首页 > 大数据 > 人工智能

2012 Multi-University Training Contest 2

2012-07-26 19:41 375 查看
看完了第一道题,感觉贪心可做,然后跟cz说了一下,他去写,然后我去看另外一道题,就这样悲剧开始了,被坑了一下午,看了一道自认为不算太难的题,然后自己写写,试了点数据感觉不怎么对,然后删了重新想,一直就在纠结,中间交流了一下其他题,在我试图暴力第二道题失败后继续思考那道题,就这样思考到了最后1个小时果断放弃去交流其他题了。最后貌似那道题只有11个队过了。。赛后看了下题解:较难的动态规划题、、、Orz。。1001 Hero

代码:

View Code 1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cstdlib>
5 using namespace std;
6 const int N=100001;
7 int map
,vis
;
8 int n,k;
9 struct Map
{
int u;
int v;
int value;
}edge
;
int comp(const void *a,const void *b)
{
return (*(struct Map *)a).value<(*(struct Map *)b).value?1:-1;
}
int find(int x)
{
int r=x;
while(map[r]!=r)
r=map[r];
return r;
}
void merge()
{
__int64 sum=0;
int i;
for(i=0;i<n-1;i++)
{
int fx=find(edge[i].u);
int fy=find(edge[i].v);
if(vis[fy]==0)
map[fy]=fx;
else if(vis[fx]==0)
map[fx]=fy;
else
sum+=edge[i].value;
}
printf("%I64d\n",sum);
}
int main()
{
int t,i,a;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
for(i=0;i<N;i++)
map[i]=i;
memset(vis,0,sizeof(vis));
for(i=0;i<n-1;i++)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].value);
}
for(i=0;i<k;i++)
{
scanf("%d",&a);
vis[a]=1;
}
qsort(edge,n-1,sizeof(edge[0]),comp);
merge();
}
return 0;
}

附:

官方题解:

1001 Hero

中等偏易题,状态压缩dp,用dp[mask]表示杀死mask集合的敌人时,这些敌人造成的最小hp消耗。有转移方程dp[mask] = min{dp[mask - {i}] + hp_sum[mask] * dps[i], for all i in mask} 1002 Meeting point-1:

平面上两点间的 Manhattan 距离为 |x1-x2| + |y1-y2|X 方向的距离与 Y 方向上的距离可以分开来处理。假设我们以 (xi,yi) 作为开会的地点,那么其余的点到该开会地点所需的时间为 X 方向上到 xi 所需要的时间加上 Y 方向上到 yi 所需要的时间。对数据预处理后可以快速地求出x坐标小于xi的点的个数rankx, 并且这些 x 坐标值之和 sumx,那么这些点 X 方向上对结果的贡献为 rankx * xi - sumx;同理可以处理出 x 坐标大于 xi 的点在 X 方向上对结果的贡献值。同理可求得其余点在 Y 方向上到达 yi 所需要的总时间。 1003 Meeting point-2:

平面上两点间的 Chebyshev距离为 max(|x1-x2|, |y1-y2|)




Chebyshev Manhattan对于原坐标系中两点间的 Chebyshev 距离,是将坐标轴顺时针旋转45度并将所有点的坐标值放大sqrt(2)倍所得到的新坐标系中的Manhattan距离的二分之一。大家可以画图想一下……假设有两点(x1,y1), (x2,y2),不妨设 x1>x2(否则交换这两点即可)。则Chebyshev距离 D1 = max(|x1-x2|, |y1-y2|)这两点个对应到新坐标系中的坐标为 (x1-y1, x1+y1), (x2-y2, x2+y2)则Manhattan 距离D2 = |x1-y1-x2+y2| + |x1+y1-x2-y2|分四种情况讨论:1.1 y1>y2 && x1-x2>y1-y2D1 = max(x1-x2, y1-y2) = x1 - x2D2 = x1-y1-x2+y2 + x1+y1-x2-y2 = 2(x1-x2)1.2 y1>y2 && x1-x2<=y1-y2D1 = max(x1-x2,y1-y2) = y1-y2D2 = -(x1-y1-x2+y2) + x1+y1-x2-y2 = 2(y1-y2)2.1 y1<=y2 && x1-x2>y2-y1D1 = max(x1-x2, y2-y1) = x1-x2D2 = x1-y1-x2+y2 + x1+y1-x2-y2 = 2(x1-x2)2.2 y1<=y2 && x1-x2<=y2-y1D1 = max(x1-x2, y2-y1) = y2-y1D2 = x1-y1-x2+y2 - (x1+y1-x2-y2) = 2(y2-y1)所以先将Chebyshev距离形式转化成Manhattan距离的形式再求解,求解过程参考 Meeting point-2

1004 Matrix:(cin,cout标程要运行2s,scanf,printf 1s)

对于有n个结点的树,容易证明删除任意的k (k<=n-1)条边都能将原树切成k+1个部分。按照题意至少需要将原树划分成d个部分(此时每部分中都包含一个危险的点),删除的边数为d-1。贪心算法:类似kruskal最小生成树的过程,不过此处将边按权值从大到小排列,每次将边加进来时要判断是否会使两个危险的点连通,是的话这条边就是需要被删除的,否则将它加到树上。树形dp:以任意一个点作为根生成树,对于每个结点保存两个值dp[u][0]: 与u连通的子孙结点中没有危险结点时需要删除的最小边权值,若u为危险结点,则该值为无穷大。dp[u][1]:与u连通的子孙结点中没有危险结点时需要删除的最小边权值。递推方程:一、u为叶子结点(1) u 是危险点dp[u][0] = inf, dp[u][1] = 0;(2) u不是危险点dp[u][0] = 0, dp[u][1] = 0;二、U不是叶子结点(1) u是危险点Dp[u][0] = inf,(2) u不是危险点 1005 Save the Dwarf

较难的动态规划题。一个重要的观察是,如果某些矮人可以逃脱,那么我们总可以把他们的逃脱顺序按照Ai+Bi递增排序(即Ai+Bi最小的先逃脱),得到的结果不会更坏。于是可以先按Ai+Bi排序处理即可。用dp[i][j]表示最后i个人能逃出j个时,需要之前井中剩下的人的最小A高度之和。有如下转移方程dp[i][j] = min(dp[i-1][j] - s[i-1].a, max(dp[i-1][j-1], H - sumA[i-1] - s[i-1].b ))。最后找到最大的j满足dp
[j]<=0即为所求。 p.s. 似乎也可以用贪心来做,但是证明比较复杂。

1006 Climb the Hill

中等博弈题。此题的简化版本是不考虑King的存在,双方一直走到不能走的一方为负。此时的解法是根据人数的奇偶性:把人从上顶向下的位置记为a1,a2,...an, 如果为偶数个人,则把a(2i-1)和a(2i)之间的距离当做一个Nim堆,变成一共n/2堆的Nim游戏;如果为奇数个人,则把山顶到a1的距离当做一个Nim堆,a(i*2)到a(i*2+1)的距离当做Nim堆,一共(n+1)/2堆。考虑King的情况和上述版本几乎一致,只要把King当作普通人一样处理即可。除了两种特殊情况:1. 当King是第一个人时,Alice直接胜 2. 当King是第二个人且一共有奇数个人时,第一堆的大小需要减1。 1007 Mission Impossible:

题目模型可以抽象为:有三个点光源,一个放在z = 0 平面的凸多面体,求三个点光源照射凸多面体在z = 0平面上的影子的公共部分。对于每个点光源,它在z = 0平面上产生的影子都是一个凸多边形,三个凸多边形的交集即为所求。凸多边形求法:每个点光源和凸多面体的每个点进行连线,和z = 0平面求交点,对于交点求凸包,即为所求凸多边形。三个凸多边形求交集:半平面交 1008 Nim

中等难度状态压缩dp题。要注意的是直觉得出的一些贪心算法往往是有反例的。基本思路是从高到低计算(从低到高也可以),用状态dp[k][mask]表示高k位如果要满足要求,并且集合mask中的数需要从低位进位时,最少需要加多少石子。 1009 Power transmission

题目大意可大致表述为从节点s向节点t传送电力,电力在传送过程中会有所消耗,不同节点之间,电力传送消耗的值有所不同。要求选择一条使得电力消耗最小的线路。如果不能把电力从s点传送到t点,或者电力损失殆尽,则输出IMPOSSIBLE!如果从s出发,没有到达t的路径,则输出IMPOSSIBLE!如果存在这样一条路径p = (s,p1,p2,p3,...,pn,t),那么最后到达t的电力为M*(1-b1%)*(1-b2%)*...*(1-bn%)*(1-bn+1%)。即我们需要找到这样一条路径,使得(1-b1%)*(1-b2%)*...*(1-bn%)*(1-bn+1%)最大。解题思路1:我们可以把乘积的形式通过取对数化作连续相加的形式即log(1-b1%) +…+log(1-bn+1%),由于 log(1-bi%)都是小于0的,我们要求这个式子的最大值就是求每个子式取绝对值的最小值。所以通过取对数在取绝对值的操作,我们可以得到两节点之间新的边权。同时题目也转化为求单源最短路问题。最后注意把结果进行转化。解题思路2:直接贪心。类似于Dijkstra算法。我们要求损耗最小,也就是剩余最大。对于每个节点,我们记录起当前可以达到的剩余最大电力。和Dijkstra算法相似,我们这里每次找寻的是尚未标记的拥有最大值的结点,并把这个最大值作为当前结点的最终结果,标记此结点并通过当前结点拓展与之相连的结点。因为从一个结点传输电力到另一个几点,电力的总量是不会增加的。所以,在以后的贪心过程中,不会更新之前已经标记的结点,因为不可能有更大的值。这样只要求得最后到达t的最大剩余电力就能得出答案。 1010 Maximum Subsequences

难题。用分治法来做,关键在于O(n)时间完成合并操作。我们把要求的结果开方,答案不变,即求max{abs(a[i]+...+a[j]) / (j-i+1)}. 设函数f(x,y) = |y| / sqrt(x),则x即为子序列长度,y即为子序列和,下面我们可以把(x,y)看作平面内的点。欲处理a[i..j]之内的最优区间,递归处理a[i..mid]和a[(mid+1)...j],然后设b1 = (1, a_mid), b2 = (2, a_mid + a_(mid-1)), b3 = (3, a_mid + a_(mid-1) + a_(mid-2))...c1 = (1, a_(mid+1)), c2 = (2, a_(mid+1)+a_(mid+2)) ...我们把bi, ci都看作二维平面内的点,分别计算出bi, ci的上凸包和下凸包,再把两个上凸包合并,两个下凸包合并,最优解一定在合并得到的凸包上。这个过程是可以O(n)完成的。两个上凸包p,q合并成t是指如下过程:t1 = p1 + q1如果ti = pj + qk, 那么t(i+1) = p(j+1) + qk 或 t(i+1) = pj + q(k+1),根据凸性决定保留哪一个下凸包的合并也是类似过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: