寒假训练(补)0129_并查集

E
poj1456

emmm,一开始用的暴力,过了。。。(数据好水,我甚至cmp忘记写在价值相同时,需要返回更大的时间了)

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef pair<int,int> P;
P a[10010];
int cmp(P a, P b)
{
	return a.first>b.first;
}
bool use[10010];
int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	int n;
	while(cin>>n)
	{
		for(int i=0;i<n;i++)
		{
			cin>>a[i].first>>a[i].second;
		}
		sort(a,a+n,cmp);
		fill(use,use+10005,true);
		int asd=0;
		for(int i=0;i<n;i++)
		{
			while(!use[a[i].second] && a[i].second>0)
			a[i].second--;
			if(use[a[i].second] && a[i].second>0)
			{
				use[a[i].second]=false;
				asd+=a[i].first;
			}
		}
		cout<<asd<<"\n";
	}
	return 0;
}

然后看了看题解,淦,居然可以拿并查集优化的
学习了下 每次更新的时候,假如这个点从未使用过的话,从-1更新为qwe-1,例如样例1的4 50 2 10 1 20 2 30 1
先是50 2,那么讲par[2]更新为1,代表1已经使用过了,再是30 1,将par[1]更新为0,那么下次查询20 2的时候,会把par[2]也更新为par[1]的值0,省去了贪心重复找的时间
重点:初始化的时候记得全部初始为-1,直接开到10000

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 10010
int par[maxn];//父亲 
int knar[maxn];//树的高度
int find(int x)//查询树的根 
{
	if(par[x]==-1)
	{
		return x;
	}
	else
	return par[x]=find(par[x]);
}
void init(int n)//初始化n个元素 
{
	for(int i=0;i<=n;i++)
	{
		par[i]=-1;
		knar[i]=0;
	}
}
void unite(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
	return ;
	if(knar[x]<knar[y])
	{
		par[x]=y;
	}
	else
	par[y]=x;
	if(knar[x]==knar[y])
	knar[x]++;
}
bool same(int x,int y)
{
	return find(x)==find(y);
}
typedef pair<int,int> P;
P a[10010];
int cmp(P a, P b)
{
	return a.first>b.first;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	int n;
	while(cin>>n)
	{
		for(int i=1;i<=n;i++)
		{
			cin>>a[i].first>>a[i].second;
		}
		sort(a+1,a+n+1,cmp);
		init(10005);
		int asd=0;
		for(int i=1;i<=n;i++)
		{
//			cout<<find(a[i].second)<<'\n';
			int qwe=find(a[i].second);
//			if(find(a[i].second)>0)
			if(qwe>0)
			{
				par[qwe]=qwe-1;
				asd+=a[i].first;
			}
		}
		cout<<asd<<"\n";
	}
	return 0;
}

F
其实感觉直接用连通图的性质就能做,但既然是并查集专项训练就用并查集呗
这题卡了我实际上1个小时。。。自做聪明的认为1必然是起点了,不用统计1号点的数据,直接输出就好,但其实因为输入顺序的不同1号点的祖先节点有可能不是1自己,比如先输入1 2时,par[1]=1,par[2]=2,而先输入2,1时,par[2]=1,par[1]=2。。。。
导致疯狂wa
在这里插入图片描述
ac代码

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 1010
int par[maxn];//父亲 
int knar[maxn];//树的高度
int find(int x)//查询树的根 
{
    if(par[x]==x)
    {
        return x;
    }
    else
    return par[x]=find(par[x]);
}
void init(int n)//初始化n个元素 
{
    for(int i=1;i<=n;i++)
    {
        par[i]=i;
        knar[i]=0;
    }
}
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y)
    return ;
    if(knar[x]<knar[y])
    {
        par[x]=y;
    }
    else
    par[y]=x;
    if(knar[x]==knar[y])
    knar[x]++;
}
bool same(int x,int y)
{
    return find(x)==find(y);
}
int main()
{
//    ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
    int n,m,a,b;
    while(cin>>n)
    {
        if(n==0)
        return 0;
        cin>>m;
        init(n+5);
        while(m--)
        {
            cin>>a>>b;
            unite(a,b);
        }
        int asd=0;
        for(int i=1;i<=n;i++)
        {
            if(find(i)==i)
            asd++;
        }
        cout<<asd-1<<"\n";
    }
    return 0;
}

那我又想了,这是因为1的祖先节点有可能被更新为其他的,那我在更新节点时,假如一个数字和1进行合并时,强制他更改为1,而不考虑树的秩呢?那我最后统计的时候是不是就可以直接从2开始统计,不用管1了呢,试了下,是可以的,但不建议你们这么试,因为为了少一次统计。。。导致其他操作变多了,很亏,我主要是不服气。。。

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 1010
int par[maxn];//父亲 
int knar[maxn];//树的高度
int find(int x)//查询树的根 
{
    if(par[x]==x)
    {
        return x;
    }
    else
    return par[x]=find(par[x]);
}
void init(int n)//初始化n个元素 
{
    for(int i=1;i<=n;i++)
    {
        par[i]=i;
        knar[i]=0;
    }
}
void unite(int x,int y)
{
	if(x==1)
	{
		par[find(y)]=find(x);
		return ;
	}
    x=find(x);
    y=find(y);
    if(x==y)
    return ;
    if(x==1)
    {
    	par[y]=x;
    	return ;
	}
	if(y==1)
	{
		par[x]=y;
		return ;
	}
    if(knar[x]<knar[y])
    {
        par[x]=y;
    }
    else
    par[y]=x;
    if(knar[x]==knar[y])
    k nar[x]++;
}
bool same(int x,int y)
{
    return find(x)==find(y);
}
int main()
{
//    ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
    int n,m,a,b;
    while(cin>>n)
    {
        if(n==0)
        return 0;
        cin>>m;
        init(n+5);
        while(m--)
        {
            cin>>a>>b;
            unite(min(a,b),max(a,b));
        }
        int asd=0;
        for(int i=2;i<=n;i++)
        {
            if(find(i)==i)
            asd++;
        }
        cout<<asd<<"\n";
    }
    return 0;
}

G
认真读题认真读题认真读题
没啥好讲的,我一开始以为2个子序列不需要连续,后来发现是连续的,那很简单了,stl大法好

#include <bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	string s1,s2,s3;
	cin>>s1>>s2>>s3;
	long long n=0,m=0;
	int qwe=0,asd=0;
	n=s1.find(s2,0);
	m=s1.find(s3,n+s2.size());
	if(n!=string::npos && m!=string::npos)
	qwe=1;
	reverse(s1.begin(),s1.end());
	n=s1.find(s2,0);
	m=s1.find(s3,n+s2.size());
	if(n!=string::npos && m!=string::npos)
	asd=1;
	if(qwe && asd)
	cout<<"both\n";
	else
	if(qwe==0 && asd==1)
	cout<<"backward\n";
	else
	if(asd==0 && qwe==1)
	cout<<"forward\n";
	else
	cout<<"fantasy\n";
	return 0;
}

H题
傻逼题

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a,b;
	cin>>a>>b;
	a=max(a,b);
	switch(a)
	{
		case 1:{
			cout<<"1/1\n";
			break;
		}
		case 2:{
			cout<<"5/6\n";
			break;
		}
		case 3:{
			cout<<"2/3\n";
			break;
		}
		case 4:{
			cout<<"1/2\n";
			break;
		}
		case 5:{
			cout<<"1/3\n";
			break;
		}
		case 6:{
			cout<<"1/6\n";
			break;
		}
	}
	return 0;
 } 

I题
更傻逼了

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n,a,b,c,q,w,y,x;
	int p1,p2,p3;
	cin>>n>>p1>>p2>>p3>>q>>w;
	int s=0;
	int ans=0; 
	for(int i=1;i<=n;i++)
	{
		cin>>x>>y;
		ans+=(y-x)*p1;
		if(s!=0)
		{
			if(x-s>w+q)
			{
				ans+=(x-s-w-q)*p3;
				ans+=w*p2;
				ans+=q*p1;
			}
			else
			if(x-s>q)
			{
				ans+=(x-s-q)*p2;
				ans+=q*p1;
			}
			else
			{
				ans+=(x-s)*p1;
			}
			
		}
		s=y;
	}
	cout<<ans<<"\n";
	return 0;
}

L题
我是傻逼

#include <bits/stdc++.h>
using namespace std;
int a[10];
int main()
{
	
	cin>>a[0];
	cin>>a[1];
	cin>>a[2];
	cin>>a[3];
	sort(a,a+4);
	int qwe=1;
	if(a[0]+a[1]>a[2])
	{
		cout<<"TRIANGLE\n";
	}
	else
	if(a[1]+a[2]>a[3])
	cout<<"TRIANGLE\n";
	else
	if(a[0]+a[1]==a[2] || a[1]+a[2]==a[3])
	{
		cout<<"SEGMENT\n";
	}
	else
	cout<<"IMPOSSIBLE\n";
	return 0;
	
}
发布了6 篇原创文章 · 获赞 10 · 访问量 5723

猜你喜欢

转载自blog.csdn.net/WWL0702/article/details/104681128