3/29 思维+并查集+最短路

P3535 [POI2012]TOU-Tour de Byteotia
本题将大于编号k的边相连组成环,若有小于等于k的边进来,并查集判断在环内,则需要累加1删去。

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,k,ans,f[N],head[N];
struct node
{
    int u,v;
}e[N];
bool cmp(node e1,node e2)
{
    if(e1.u==e2.u) return e1.v>e2.v;
    return e1.u>e2.u;
}
int r_find(int r)
{
    if(f[r]==r)
        return f[r];
    f[r]=r_find(f[r]);
    return f[r];
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
        cin>>e[i].u>>e[i].v;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(e[i].u>k&&e[i].v>k)
        {
            int fx=r_find(e[i].u),fy=r_find(e[i].v);
            f[fx]=fy;
        }
        else
        {
            int fx=r_find(e[i].u),fy=r_find(e[i].v);
            if(fx==fy)
            {
                ans++;continue;
            }
            f[fx]=fy;
        }
    }
    cout<<ans<<endl;
	return 0;
}

P4047 [JSOI2010]部落划分

题意:聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离
处理技巧:将距离从小到大排序,每次合并一个部落就达到了使靠得最近的两个部落尽可能远离
(避免二分,用最小生成树变型)

n个部落:需要n-1条边变成一个部落
k个部落:k-1条边连接到k个部落
(n-1)-(k-1)条边使得部落变为k个部落==n-k条边组成k个部落
因此两个部落尽可能远离,答案为n-k+1点的距离

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,k,ans,num,f[N],a[N],b[N],cnt;
struct node
{
    int u,v;double dis;
}e[N];
bool cmp(node e1,node e2)
{
    return e1.dis<e2.dis;
}
int r_find(int r)
{
    if(f[r]==r)
        return f[r];
    f[r]=r_find(f[r]);
    return f[r];
}
int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    cout << fixed << setprecision(2);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i]>>b[i],f[i]=i;
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
    {
        double dd=sqrt((double)(a[i]-a[j])*(a[i]-a[j])+(double)(b[i]-b[j])*(b[i]-b[j]));
        e[++cnt].u=i,e[cnt].v=j,e[cnt].dis=dd;
    }
    sort(e+1,e+cnt+1,cmp);
    int i;
    for(i=1;i<=cnt;i++)
    {
        //cout<<e[i].dis<<endl;
        int fx=r_find(e[i].u),fy=r_find(e[i].v);
        if(fx!=fy)
        {
            f[fx]=fy;num++;
        }
        if(num==n-k+1) break;
    }
    cout<<e[i].dis<<endl;
	return 0;
}

P1073 [NOIP2009 提高组] 最优贸易
vector做法,比链式前向行更方遍,我感觉。照着大佬的思路和码风写了一遍,收获挺多。

#include <bits/stdc++.h>
#define t(x,i) (n*i+x)
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int n,m,dist[N*3],vis[N*3];
vector<pair<int,int> >g[N*3];
void add(int x,int y)
{
    g[t(x,0)].push_back({t(y,0),0});
    g[t(x,1)].push_back({t(y,1),0});
    g[t(x,2)].push_back({t(y,2),0});
}
void spfa(int u)
{
    for(int i=1;i<=n*3;i++) dist[i]=-inf;
    dist[u]=0;
    queue<int>q;q.push(u);
    vis[u]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(auto &k :g[u])
        {
            int v=k.first,len=k.second;
            if(dist[v]<dist[u]+len)
            {
                dist[v]=dist[u]+len;
                if(!vis[v]) q.push(v),vis[v]=1;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    cout << fixed << setprecision(2);
    cin>>n>>m;
    for(int i=1,v;i<=n;i++)
    {
        cin>>v;
        g[t(i,0)].push_back({t(i,1),-v});
        g[t(i,1)].push_back({t(i,2),v});
    }
    for(int i=1,x,y,z;i<=m;i++)
    {
        cin>>x>>y>>z;add(x,y);
        if(z==2) add(y,x);
    }
    spfa(t(1,0));
    cout<<dist[t(n,2)]<<endl;
	return 0;
}

CF

CF14B Young Photographer
这个绿题还是蛮简单的,思路一般般,题意得想清楚。我就是刚开始没读明白题意~

#include <bits/stdc++.h>
#define t(x,i) (n*i+x)
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int n,k,num[1005],mi=inf;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        int x,y;cin>>x>>y;
        if(x>y) swap(x,y);
        for(int g=x;g<=y;g++)
            num[g]++;
    }
    int g=mi;
    for(int i=0;i<=1000;i++)
    {
        //cout<<num[i]<<endl;
        if(num[i]==n)
            mi=min(mi,abs(i-k));
    }
    if(g!=mi)
        cout<<mi<<endl;
    else
        cout<<-1<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值