【数字_ID】CUC Spring 题解

How Many Answers Are Wrong HDU - 3038

带权并查集,对于任何一个 u , v , w , ( u &lt; v ) u,v,w,(u&lt;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 &gt; = s t [ i ] . s e t s i z e   &amp; &amp;   d p [ i − 1 ] [ j − s t [ i ] . s e t s i z e ] &gt; 0 ) ) dp[i][j] += dp[i-1][j - st[i].setsize] (if\ (j &gt;= st[i].setsize\ \&amp;\&amp;\ dp[i-1][j - st[i].setsize]&gt;0)) dp[i][j]+=dp[i1][jst[i].setsize]if (j>=st[i].setsize && dp[i1][jst[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);
		
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值