文章目录
How Many Answers Are Wrong HDU - 3038
带权并查集,对于任何一个 u , v , w , ( u < v ) u,v,w,(u<v) u,v,w,(u<v) , 表示, [ u , v + 1 ) [u,v+1) [u,v+1)的值之和, v a l [ u ] val[u] val[u]便是 u u u到其 f a t h e r + 1 father+1 father+1的和,判断是否有矛盾,具体矛盾点代码中可见,emmm这道题各种wa,当时调还挺痛苦的(还是自己太菜)。多组样例题目也不说,真的是坑。
#include <iostream>
#include <string.h>
#include <algorithm>
#define debug(x); cout << __LINE__ << ": name : " << #x << " "<<x<<endl;
using namespace std;
const int maxn = 200020;
int fa[maxn];
int val[maxn];
void init()
{
for(int i = 0;i<maxn;i++){
fa[i] = i;
val[i] = 0;
}
}
int find(int x)
{
if(fa[x] == x)return fa[x];
else{
int f = find(fa[x]);
val[x] += val[fa[x]];
fa[x] = f;
return fa[x];
}
}
int main()
{
int n;
int m;
while(~scanf("%d%d",&n,&m)){
init();
int ans = 0;
for(int i = 0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(w < u - v + 1){
ans ++;
continue;
}
if(u>v)swap(u,v);
v ++;
int xx = find(u);
int yy = find(v);
//if(xx > yy)swap(xx,yy);
if(xx == yy){
if(val[u] == 0 ){
//debug(u);debug(v);
ans ++ ;
continue;
}else if(val[u] - val[v] != w){
//debug(u);debug(v);debug(val[u]);debug(val[v]);
ans ++;
continue;
}
}else{
//debug(u);debug(v);
//debug(xx);debug(yy);
if(xx > yy)
{
int t = val[u] - val[v] - w;
//debug(xx);
//debug(t);
if(t <0){
ans ++;
continue;
}else{
fa[yy] = xx;
val[yy] = t;
}
}else{
int t = w - val[u];
//debug(t);
if(t < 0){
ans ++ ;
continue;
}else{
fa[xx] = yy;
val[xx] = t + val[v];
}
}
}
}
printf("%d\n" , ans);
}
}
/*
10 3
1 10 20
1 5 30
5 7 1
10 2
3 3 1
3 3 1
*/
True Liars POJ - 1417
这道题的关键就是,如果一个人说另一个人是好人,那么他们俩肯定是一个阵营的,如果一个人说另一个人是坏人,那么他们俩一定是不同阵营的。
带权并查集,val[x]
表示x和他的父亲的关系,0位同类,1为敌对,路径压缩的时候,异或即可,merge时的操作可以自行理解
然后我们得到了m个集合,这些集合有些和father是敌对关系,有些和father是朋友关系,但我们不知道哪些是好人,哪些是坏人。我们有从这些集合中选出一些同类,使得人数是好人的人数,判断是否是唯一解,这就是一个背包问题了。
我们有st结构体数组,把每个集合分成两类
dp[i][j]
表示前i个集合,选出j个好人的方案
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
−
s
t
[
i
]
.
s
e
t
s
i
z
e
]
(
i
f
(
j
>
=
s
t
[
i
]
.
s
e
t
s
i
z
e
&
&
d
p
[
i
−
1
]
[
j
−
s
t
[
i
]
.
s
e
t
s
i
z
e
]
>
0
)
)
dp[i][j] += dp[i-1][j - st[i].setsize] (if\ (j >= st[i].setsize\ \&\&\ dp[i-1][j - st[i].setsize]>0))
dp[i][j]+=dp[i−1][j−st[i].setsize](if (j>=st[i].setsize && dp[i−1][j−st[i].setsize]>0))
dp也是个结构体,因为要打印答案
#include <iostream>
#include <string.h>
#include <algorithm>
#include <vector>
#include <algorithm>
#include <stdio.h>
#define debug(x); cout << __LINE__ << ": name : " << #x << " "<<x<<endl;
using namespace std;
const int maxn = 1020;
int fa[maxn];
int val[maxn];
int cnt;
int n,p1,p2;
bool vis[maxn];
int id[maxn];
vector<int>ans;
struct St{
int setasize,setbsize;
vector<int> seta;
vector<int> setb;
}st[maxn];
struct Dp{
int pre;
int val;
}dp[maxn][maxn];
void init(int n)
{
cnt = 1;
ans.clear();
for(int i = 0;i<=n;i++){
fa[i] = i;
val[i] = 0;
st[i].setasize = st[i].setbsize = 0;
st[i].seta.clear();
st[i].setb.clear();
vis[i] = 0;
for(int j = 0;j<=n;j++){
dp[i][j].pre = dp[i][j].val = 0;
}
}
dp[0][0].val = 1;
}
int find(int x)
{
if(fa[x] == x)return fa[x];
else{
int f = find(fa[x]);
val[x] = val[x] ^ val[fa[x]];
fa[x] = f;
return fa[x];
}
}
void merge(int x,int y,int v)
{
int xx = find(x);
int yy = find(y);
if(xx != yy){
fa[xx] = yy;
if(v)val[xx] = !(val[x] ^ val[y]);
else val[xx] = val[x] ^ val[y];
}
}
int main()
{
char tmp[5];
while(~scanf("%d%d%d",&n,&p1,&p2))
{
//并查集
if(n == 0 && p1 == 0 && p2 == 0)break;
init(p1+p2);
for(int i = 0;i<n;i++){
int u,v;
scanf("%d%d%s" , &u,&v,tmp);
if(tmp[0] == 'n'){
merge(u,v,1);
}else{
merge(u,v,0);
}
}
//得到集合
for(int i = 1;i<=p1+p2;i++){
int f = find(i);
if(!vis[f]){
vis[f] = 1;
if(!val[i]){
st[cnt].setasize++;
st[cnt].seta.push_back(i);
}else{
st[cnt].setbsize++;
st[cnt].setb.push_back(i);
}
id[i] = id[f] = cnt;
cnt ++;
}else{
if(!val[i]){
st[id[f]].setasize++;
st[id[f]].seta.push_back(i);
}else{
st[id[f]].setbsize++;
st[id[f]].setb.push_back(i);
}
id[i] = id[f];
}
}
//背包
for(int i = 1;i<cnt;i++){
for(int j = 0;j<=p1;j++){
if(j >= st[i].setasize && dp[i-1][j-st[i].setasize].val>0){
dp[i][j].val += dp[i-1][j-st[i].setasize].val;
dp[i][j].pre = j - st[i].setasize;
}
if(j >= st[i].setbsize && dp[i-1][j-st[i].setbsize].val>0){
dp[i][j].val += dp[i-1][j-st[i].setbsize].val;
dp[i][j].pre = j - st[i].setbsize;
}
}
}
//不唯一
if(dp[cnt-1][p1].val != 1)
{
printf("no\n");
continue;
}
for(int i = cnt-1 , j = p1;i>=1;j = dp[i][j].pre , i--)
{
int tmp = j -dp[i][j].pre;
if(tmp == st[i].setasize){
for(int k = 0;k<st[i].setasize;k++)ans.push_back(st[i].seta[k]);
}else{
for(int k = 0;k<st[i].setbsize;k++)ans.push_back(st[i].setb[k]);
}
}
sort(ans.begin(),ans.end());
int sz = ans.size();
for(int i = 0;i<sz;i++)printf("%d\n" , ans[i]);
printf("end\n");
}
}
Is It A Tree? POJ - 1308
一道简单的并查集的题 , 还考一些对树的基本理解,数据范围没说,开了1000000发现没毛病。
在合并的过程中,如果儿子节点已经有其他父亲了,或者两个节点之间有多条边,或者自己连自己 ,就不是一棵树,就酱。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <vector>
#include <algorithm>
#include <stdio.h>
#define debug(x); cout << __LINE__ << ": name : " << #x << " "<<x<<endl;
using namespace std;
const int maxn = 1000000 + 20;
int fa[maxn];
bool vis[maxn];
bool flag;
int cnt,a,b,tt,mx;
void init()
{
for(int i = 0;i<maxn;i++)fa[i] = i , vis[i] = false;
flag = true;
cnt = 0;
}
int find(int x)
{
return (fa[x] == x)?fa[x] : fa[x] = find(fa[x]);
}
bool merge(int a , int b)
{
int xx = find(a) , yy = find(b);
if(yy != b || xx == yy)return false;
fa[yy] = xx;
return true;
}
int main()
{
tt = 1;
init();
while(~scanf("%d%d" , &a , &b)){
if(a == -1 && b == -1)break;
mx = max(max(mx , a) , b);
if(a == 0 && b == 0){
for(int i = 1;i<=mx ;i++){
if(vis[i] && fa[i] == i)cnt ++;
if(cnt > 1)flag = false;
}
if(!flag)printf("Case %d is not a tree.\n", tt++);
else printf("Case %d is a tree.\n", tt++);
init();
continue;
}
vis[a] = vis[b] = true;
if(!merge(a,b))flag = false;
}
}
Park Visit Hdu 4607
k <= 直径 :ans = k-1
k > 直径 : ans = 直径 + (k-1)* 2
#include <iostream>
#include <string>
#include <string.h>
#include <cstring>
#include <algorithm>
#include <stdio.h>
#include <queue>
#define ll long long
using namespace std;
#define INF 0x3f3f3f3f;
const ll maxn = 2e5+20;
int head[maxn];
bool vis[maxn];
int cnt = 0;
int u,v,n,m,last;
struct Edge{
int to,next;
}edge[maxn];
void init()
{
for(int i = 0;i<maxn;i++)head[i] = -1 , vis[i] = 0;
cnt = 0;
}
void addedge(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
struct node{
int x,step;
};
int bfs(int now)
{
node st = (node){now , 0};
for(int i = 0;i<=n;i++)vis[i] = 0;
queue<node>Q;
Q.push(st);
int pos = -1;
int mx = -1;
while(!Q.empty())
{
node t = Q.front();
Q.pop();
if(mx < t.step){
mx = t.step;
pos = t.x;
}
int from = t.x;
for(int i = head[from];~i;i = edge[i].next){
int to = edge[i].to;
if(!vis[to]){
vis[to] = true;
Q.push((node){to,t.step+1});
}
}
}
u = pos;
return mx;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i = 0;i<n-1;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
bfs(1);
int dis = bfs(u);
while(m--){
int tmp;scanf("%d",&tmp);
int ans = (tmp-1 > dis)?(dis + (tmp-1 - dis)*2):(tmp-1) ;
printf("%d\n",ans);
}
}
}
二叉搜索树 HDU - 3791
这道题点不多,我用数组存
#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
#include<string>
#include<stdio.h>
#define clr(x,b) memset(x,(b),sizeof(x))
#define fuck cout<<"fuck"<<endl;
#define LSon(x) 2*(x)
#define RSon(x) 2*(x)+1
using namespace std;
typedef long long ll;
int tr[1020];
int tr1[1020];
int n;
int j;
string s;
int main()
{
while(cin>>n){
cin>>s;
clr(tr,-1);
for(int i = 0;i<s.length();i++){
j = 1;
while(tr[j]!=-1){
if(s[i]-'0'<tr[j])j = LSon(j);
else j = RSon(j);
}
tr[j] = s[i]-'0';
}
while(n--){
cin>>s;
clr(tr1,-1);
for(int i = 0;i<s.length();i++){
j = 1;
while(tr1[j]!=-1){
if(s[i]-'0'<tr1[j])j = LSon(j);
else j = RSon(j);
}
tr1[j] = s[i]-'0';
}
for( j = 0;j<=1000;j++){
if(tr1[j]!=tr[j])break;
}
if(j>1000)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
}
是二叉搜索树吗?HihoCoder - 1616
不难,掌握二叉搜索树的定义即可,就是我写残了,代码比较屎。自己用vector存的,注意几种error的判断,不要少考虑了
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<math.h>
#include <stdio.h>
#include <time.h>
#include <map>
#include <vector>
using namespace std;
const int maxn = 10020;
vector<int>V[maxn];
vector<int>tmp;
int cnt,x,y,u,v,n,root;
int fa[maxn];
bool vis[maxn] , flag , flag2;
void init(int n)
{
for(int i = 0;i<=n;i++){fa[i] = 0 ; V[i].clear() ; vis[i] = 0;}
tmp.clear();
}
void dfs(int now)
{
cnt ++;
vis[now] = true;
int sz = V[now].size();
if(sz > 2){
flag = false;
}
if(sz == 0)tmp.push_back(now);
sort(V[now].begin() , V[now].end() );
for(int i = 0;i<sz;i++)
{
int to = V[now][i];
if(vis[to]){
flag2 = false;
}
else{
if(sz == 1 && V[now][0] >= now){
tmp.push_back(now);
dfs(to);
}else if(i == 0){
dfs(to);
tmp.push_back(now);
}else{
dfs(to);
}
}
}
}
bool check()
{
for(int i = 0;i<n-1;i++){
if(tmp[i+1] < tmp[i])return false;
}
return true;
}
void print(int now)
{
int sz = V[now].size();
printf("(%d",now);
if(sz == 1 && V[now][0] <= now){
print(V[now][0]);
printf("()");
}
else if(sz == 1 && V[now][0] > now){
printf("()");
print(V[now][0]);
}
else if(sz == 0)printf("()()");
else{
print(V[now][0]);
print(V[now][1]);
}
printf(")");
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
root = 0;
scanf("%d" , &n);
init(n);
cnt = 0;
flag = true;
flag2 = true;
for(int i = 0 ;i < n-1;i++){
scanf("%d%d" , &u , &v);
V[u].push_back(v);
fa[v] = u;
}
for(int i = 1;i<=n;i++){
if(!fa[i]){
root = i;
break;
}
}
if(!root){
printf("ERROR1\n");
continue;
}
//cout << root << endl;
dfs(root);
if( cnt < n||(!flag2)){
printf("ERROR1\n");
continue;
}
else if(!flag){
printf("ERROR2\n");
continue;
}else if(!check()){
printf("ERROR3\n");
continue;
}
else{
print(root);
printf("\n");
}
}
}
食物链 poj1182
网上经典的题解有很多,上课我也讲了,就不多说了
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxn = 50020;
int fa[maxn],val[maxn];//val数组表示每个节点和其father的关系,0表示同类,1表示吃父亲,2表示被吃
int n,k;
void init()
{
for(int i = 0;i<n;i++)
{
fa[i] = i;
val[i] = 0;
}
}
int find(int x)
{
if(fa[x] == x)return fa[x];
else
{
int temp = fa[x];
fa[x] = find(fa[x]);
val[x] = (val[x]+val[temp])%3;
return fa[x];
}
}
void merge(int x,int y,int t)
{
int fx = find(x);
int fy = find(y);
if(fx!=fy)
{
fa[fx] = fy;
val[fx] = (val[y]-val[x]+t+3)%3;
}
}
bool isOK(int x,int y,int t)
{
if(x>n||y>n)return false;
if(x == y&&t!=0)return false;
if(find(x) == find(y))
{
return (val[x]-val[y]+3)%3 == t;
}
else return true;
}
int main()
{
scanf("%d%d",&n,&k);
int ans = 0;
int x,y,t;
init();
while(k--)
{
scanf("%d%d%d",&t,&x,&y);
if(isOK(x,y,t-1))
{
merge(x,y,t-1);
}
else ans++;
}
cout<<ans<<endl;
return 0;
}
HDU4751 二分图染色
不认识的人之间建边,遍历图,相邻点之间染不同颜色。判断最后能否染色,即能否分成两个组
#include <iostream>
#include <stdio.h>
using namespace std;
const int maxn = 1020;
int head[maxn];
int color[maxn];
bool know[maxn][maxn];
bool flag;
int n , cnt , now , x;
void init(){
for(int i = 0;i<maxn;i++){
head[i] = -1;
color[i] = 0;
for(int j = 0;j<maxn;j++){
know[i][j] = 0;
}
}
cnt = 0;
}
struct Edge{
int to,next;
}edge[maxn];
void addedge(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
bool dfs(int now,int col)
{
color[now] = col;
for(int i = head[now];~i;i = edge[i].next){
int to = edge[i].to;
if(color[now] == color[to])return false;
if(!color[to]){
if(!dfs(to,3-col))return false;
}
}
return true;
}
int main()
{
while(~scanf("%d",&n))
{
init();
now = 1;
while(1)
{
scanf("%d",&x);
while(x)
{
know[now][x] = 1;
scanf("%d",&x);
}
if(now == n)break;
now++;
}
for(int i = 1;i<=n;i++){
for(int j = i+1;j<=n;j++){
if(!know[i][j] || !know[j][i]){
addedge(i,j);
addedge(j,i);
}
}
}
flag = true;
for(int i = 1;i<=n;i++){
if(!color[i]){
if(!dfs(i,1)){
flag = false;
break;
}
}
}
printf((flag)?"YES\n":"NO\n");
}
}
How Many Tables HDU - 1213
并查集裸题
#include <iostream>
#include <string>
#include <string.h>
#include <cstring>
#include <algorithm>
#include <stdio.h>
#include <queue>
#define ll long long
using namespace std;
#define INF 0x3f3f3f3f;
const ll maxn = 2e5+20;
int m,n;
int fa[maxn];
void init(int n){
for(int i = 0;i<=n;i++)fa[i] = i;
}
int find(int x){
return (fa[x] == x)?x:fa[x] = find(fa[x]);
}
void merge(int x,int y){
int fx = find(x),fy = find(y);
if(fx != fy)fa[fx] = fy;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d" , &n , &m);
init(n);
int ans = 0;
while(m--){
int u,v;scanf("%d%d",&u,&v);
merge(u,v);
}
for(int i = 1;i<=n;i++){
if(i == find(i))ans ++;
}
printf("%d\n",ans);
}
}