题意:

你有n种装备,每种装备有两个属性值,你要在这两个属性值里选一个,使得这些属性值是1、2、3、4......这些从1开始连续的数,题目求最多能连续到多少。

思路:

假设这些连在一起的数都在一个连通块里,那么如果这个连通块内有大于n-1条边,连通块内里的数就都能用上,否则就只能用到这个连通块内第二大的数。可以用并查集来维护连通块,也可以用dfs来维护。

代码:

dfs

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=10100;
int n;
vector<int> edge[N];
bool vis[N];
int maxn=0;

bool dfs(int x,int fa)//fa是从哪一个点来的
{
    maxn=max(x,maxn);//找这个连通块内最大的数
    vis[x]=1;
    int flag=0;//看一下是棵树,还是比树的边数还多
    for(int i=0;i<edge[x].size();i++)
    {
        int j=edge[x][i];
        if(j==fa) continue;//如果它们是一个环,那就跳过
        if(vis[j]) {flag=1;continue;}//如果之前走过,那么说明这个连通块内的边比树的边数多。
        if(dfs(j,x)) flag=1;
    }
    return flag;
}

int main(){
    cin>>n;
    int m=0;
    while(n--)
    {
        int a,b;
        cin>>a>>b;
        edge[a].push_back(b);
        edge[b].push_back(a);
        m=max(m,a);
        m=max(m,b);
    }
    int ans=m+1;//ans是假设比最大还大1的攻击次数
    memset(vis,0,sizeof vis);
    for(int i=1;i<=m;i++)//去搜索每个点所在的连通块
    {
        maxn=0;//每次都要清零
        if(!vis[i] && !dfs(i,0))//如果这个点所在的连通块是一棵树,就去更新答案,如果比树还多一条边,那么这个连通块内的点都能到,就不用任何操作了。
            ans=min(ans,maxn);
        //cout<<ans<<endl;
    }
    cout<<ans-1<<endl;
    
    return 0;
}

并查集

#include<iostream>
#include<algorithm>
using namespace std;
const int N=10010;
int fa[N],maxn[N];//maxn是比各个根结点最大的攻击次数还多1的攻击次数
bool b[N];//b是看各个根结点是不是有比n-1条边还多的边
int n;

int find(int x)
{
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

int main(){
    for(int i=1;i<N;i++)
      fa[i]=i,maxn[i]=i;
    
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        int fx=find(x);
        int fy=find(y);
        if(fx != fy)//如果根结点不一样
        {
            fa[fx]=fy;
            maxn[fy]=max(maxn[fx],maxn[fy]);//因为根结点变成fy,所以只用更新fy
            b[fy]=(b[fx] || b[fy]);//两个集合中只要有一个是有多至少一条边的,那么这两个集合合并后,集合里的每个数都能用上
        }
        else//根结点一样
        {
            b[fx]=1;//多连了一条边
        }
    }
    int ans=10001;
    for(int i=1;i<=10000;i++)
    {
        if(fa[i] == i)
        {
            if(b[i]==0)//如果集合内不能用上所有数
                ans=min(ans,maxn[i]);
        }
    }
    
    cout<<ans-1<<endl;
    
    return 0;
}