查并集—亲戚
【题目描述】
或许你并不知道,你的某个朋友是你的亲戚。他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。如果能得到完整的家谱,判断两个人是否是亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及。在这种情况下,最好的帮手就是计算机。为了将问题简化,你将得到一些亲戚关系的信息,如Marry和Tom是亲戚,Tom和Ben是亲戚,等等。从这些信息中,你可以推出Marry和Ben是亲戚。请写一个程序,对于我们的关于亲戚关系的提问,以最快的速度给出答案。
【输入】
接下来m行,每行a b c, 表示城市a与城市b有长度为c的路。输入由两部分组成。
第一部分以N,M开始。N为问题涉及的人的个数(1≤N≤20000)。这些人的编号为1,2,3,…, N。下面有M行(1≤M≤1000000),每行有两个数ai,biai,bi,表示已知aiai和bibi是亲戚。
第二部分以Q开始。以下Q行有Q个询问(1≤ Q ≤1000000),每行为ci,di,表示询问ci和di是否为亲戚。
【输出】
对于每个询问ci,di,输出一行:若ci和di为亲戚,则输出“Yes”,否则输出“No”。
【输入样例】
10 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
3 4
7 10
8 9
【输出样例】
Yes
No
Yes
对于这个题一开始我想的是两种思路,一种是不断扩大朋友圈的范围,这个思路想了很多,觉得好难实现,想用个一维数组,quan[n]=m;n是第几个人,m就是他所在的朋友圈的编号,想不到怎么实现。另一种思路,就是硬认朋友,两个人认朋友之后,两个人分别介绍自己的朋友,这个思路很简单,就是复杂度太高,不过这个方法有个好处就是把输入的人数给用上了。
void fly(int a,int b){
for(i=1;i<=n;i++)
if(dp[a][i]==1)
{
dp[i][b]=1;
dp[b][i]=1;
}
}
int main(){
cin>>n>>m;
for(i=1;i<=m;i++)
{
cin>>t>>T;
dp[t][T]=1;
dp[T][t]=1;
fly(t,T);
fly(T,t);
}
后来还是看的别人的代码,才了解到这个精妙的算法,用一对朋友左边的朋友的朋友圈编号给右边的朋友,朋友圈的编号用用初代朋友来表示,以此来不断扩大朋友圈,具体细节在都在代码中
#include <iostream>
using namespace std;
const int N = 10010;
int f[N];
int getFriend(int v) {
if(f[v] == v) {
return v;
}
//
如果发现“朋友祖先”不是自己,那么他肯定被合并到别的朋友圈里面去了,
那么继续调用这个函数来找这个朋友圈里面的“朋友祖先”,
return f[v] = getFriend(f[v]);
}
void bing(int a, int b) {
int t = getFriend(a);
int T = getFriend(b);
if(t != T) {
f[t] = T;
}
}
int main() {
int n, m, k;
cin >> n >> m >> k;
int x, y;
for(int i = 1; i <= n; i++)
f[i] = i;
for(int i = 0; i < m; i++) {
cin >> x >> y;
bing(x, y);
}
for(int i = 0; i < k; i++) {
cin >> x >> y;
if(getFriend(x) != getFriend(y)) {
cout << "no" << endl;
} else {
cout << "yes" << endl;
}
}
return 0;
}
经典背包-多重背包
Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
Input
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
当时做这个题错了好几次都不知道是为什么,过了很长时间才明白原来这题的题意是求一共有多少种钱数,而不是最大钱数,样例答案也都对上了,真的没想到。。背包问题,感觉都是老师讲过的模型,多重背包,可以先判断容量与数量乘以价值谁大,如果超过了容量可以直接用完全背包的形式写这样稍微会快一点,else,就用多重背包直接做。用多重背包的时候可以用2进制优化,不过我没用也过了,还是复习一下比较好,k的增加以2倍增加,然后每次k用完要把w【i】减掉k,后面再判断w【i】大于0,再进行一个max选择,背包问题我感觉还是比较简单的,但是写起来还是会一波三折,果然还是要多练才能真正变强啊。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
int v[110];
int w[110];
int dp[100005];
using namespace std;
int max(int a,int b){return a>b?a:b;}
int main()
{
int chongle;
int n,m;
int i,j,k;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
memset(v,0,sizeof(v));
memset(w,0,sizeof(w));
for( i=1;i<=100005;i++)
dp[i]=-9999999;
dp[0]=0;
for(i=1; i<=n; i++)
scanf("%d",&v[i]);
for( i=1; i<=n; i++)
scanf("%d",&w[i]);
for( i=1; i<=n; i++)
{
if(v[i]*w[i]>=m)
{
for( j=v[i]; j<=m; j++)
{
dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
}
}
else
{
for( k=1; k<=w[i]; k++)
{
for(j=m; j>=v[i]*k; j--)
{
dp[j]=max(dp[j],dp[j-v[i]*k]+v[i]*k);
}
}
}
}
int count=0;
for(i=1; i<=m; i++)
{
if(dp[i]>0)
count++;
}
cout<<count<<endl;
}
return 0;
}
区间dp-wolf
Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not all, Dire Wolves appear to originate from Draenor.
Dire wolves look like normal wolves, but these creatures are of nearly twice the size. These powerful beasts, 8 - 9 feet long and weighing 600 - 800 pounds, are the most well-known orc mounts. As tall as a man, these great wolves have long tusked jaws that look like they could snap an iron bar. They have burning red eyes. Dire wolves are mottled gray or black in color. Dire wolves thrive in the northern regions of Kalimdor and in Mulgore.
Dire wolves are efficient pack hunters that kill anything they catch. They prefer to attack in packs, surrounding and flanking a foe when they can.
— Wowpedia, Your wiki guide to the World of Warcra
Matt, an adventurer from the Eastern Kingdoms, meets a pack of dire wolves. There are N wolves standing in a row (numbered with 1 to N from left to right). Matt has to defeat all of them to survive.
Once Matt defeats a dire wolf, he will take some damage which is equal to the wolf’s current attack. As gregarious beasts, each dire wolf i can increase its adjacent wolves’ attack by b i. Thus, each dire wolf i’s current attack consists of two parts, its basic attack ai and the extra attack provided by the current adjacent wolves. The increase of attack is temporary. Once a wolf is defeated, its adjacent wolves will no longer get extra attack from it. However, these two wolves (if exist) will become adjacent to each other now.
For example, suppose there are 3 dire wolves standing in a row, whose basic attacks ai are (3, 5, 7), respectively. The extra attacks b i they can provide are (8, 2, 0). Thus, the current attacks of them are (5, 13, 9). If Matt defeats the second wolf first, he will get 13 points of damage and the alive wolves’ current attacks become (3, 15).
As an alert and resourceful adventurer, Matt can decide the order of the dire wolves he defeats. Therefore, he wants to know the least damage he has to take to defeat all the wolves.
Input
The first line contains only one integer T , which indicates the number of test cases. For each test case, the first line contains only one integer N (2 ≤ N ≤ 200).
The second line contains N integers a i (0 ≤ a i ≤ 100000), denoting the basic attack of each dire wolf.
The third line contains N integers b i (0 ≤ b i ≤ 50000), denoting the extra attack each dire wolf can provide.
Output
For each test case, output a single line “Case #x: y”, where x is the case number (starting from 1), y is the least damage Matt needs to take.
Sample Input
2 3 3 5 7 8 2 0 10 1 3 5 7 9 2 4 6 8 10 9 4 1 2 1 2 1 4 5 1
Sample Output
Case #1: 17 Case #2: 74
这题刚开始去想还会想成是贪心的题目,但是这是动态的,不能那样做。可以用区间dp做,枚举区间。
dp[i][j]的意义就是从杀从i到j这几只狼会受到的最小伤害,这里枚举区间的方程是max(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1])因为不管顺序是啥都要收到 i - 1 和 j + 1 只狼的辅助伤害。这部分伤害是不包括在两个dp中的,这个地方我刚开始也没想到。因此这里还要设置b【0】b【n+1】都是0.
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long int
#define INF 0x3f3f3f3f
#define N 220
using namespace std;
int a[N],b[N],dp[N][N];
int min(int a,int b)
{
return a>b?b:a;
}
int main()
{
int t,cas=1;
int i,j,k,len;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(i=1; i<=n; i++)
cin>>a[i];
for(i=1; i<=n; i++)
cin>>b[i];
b[0]=b[n+1]=0;
memset(dp,0,sizeof(dp));
for( i=1; i<=n; i++)
for( j=i; j<=n; j++)
dp[i][j]=INF;
for( len=1; len<=n; len++)
for( i=1; i<=n-len+1; i++)
{
j=i+len-1;
for( k=i; k<=j; k++)
dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]);
}
printf("Case #%d: %d\n",cas++,dp[1][n]);
}
return 0;
}
本文探讨了查并集算法在亲戚关系判断中的应用,通过建立朋友圈模型解决复杂亲戚关系查询问题。同时,深入解析了多重背包问题的解决策略,采用动态规划优化算法效率,以及如何应对区间DP挑战,通过实例说明算法设计与优化技巧。
1404

被折叠的 条评论
为什么被折叠?



