poker P3793

Description

小F和小Z正在玩扑克牌。他们的扑克牌非常奇怪,正反两面都印有数字,分别是a[i],b[i]。一开始,桌面上摆着n张扑克牌。这个游戏一共进行n-1轮,每一轮他们可以选择两张扑克牌i,j,然后从中丢弃一张,剩下的一张放回桌面上。那么这一轮中他们的得分为min(a[i]^b[j],a[j]^b[i]).其中^表示异或。现在,小 F和小Z想知道这个游戏最少能拿多少分呢?


Input

每个测试点包含多组数据。输入数据的第一行为C,为数据个数。每组数据的第一行为n;接下来一行n个正整数表示每张牌正面的数字,接下来一行n个正整数表示每张牌反面的数字。

Output

每组数据输出一行,为这个游戏的最小得分。

Hint

样例解释:对于第二组数据,消除方案是,第一次选择第一张和第二张牌,扔掉第二张,得分为 3,第二次选择剩下的两张牌,得分为 2。

数据规模与约定:对于20%的数据,n<=10。对于40%的数据,n<=20对于 70%的数据,n<=100对于100%的数据,有1<=n<=3000,一个测试点中所有n的和<=10^4.

Solution

这道题乍一看觉得是kruskal但是如果仔细看一下Hint就会发现其实用kruskal会 超 时(kruskal的时间复杂度是(m*logm,对于稀疏图适用)。And对于这道题,他是个稠密图,所以适用prim计算最小生成树(prim的时间复杂度是n^2),所以就没了。


注意事项:
1.只需要memset(vis,false,sizeof(vis));因为其他的变量已经在init()或者prim()的过程中更新了。
2.只有一条看起来不好看。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 3005
#define inf 0x3f3f3f3f
using namespace std;
struct data{
    int leftt;
    int rightt;
}cardd[maxn];
int g[maxn][maxn],minn[maxn],minp,minw;
bool vis[maxn];
int n,T;
long long sumv;
void Clear(){
    //memset(g,inf,sizeof(g));
    memset(vis,false,sizeof(vis));
    //memset(minn,inf,sizeof(minn));
    minp=minw=sumv=n=0;
    //memset(cardd,0,sizeof(cardd));
}
void init(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&cardd[i].leftt);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&cardd[i].rightt);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            g[i][j]=min(cardd[i].leftt^cardd[j].rightt,cardd[i].rightt^cardd[j].leftt);
        }
    }
}
void prim(){
    for(int i=1;i<=n;i++){
        minn[i]=g[1][i];
    }
    vis[1]=true;
    minn[1]=0;
    for(int i=1;i<n;i++){
        minw=inf;
        for(int j=1;j<=n;j++){
            if(minw>minn[j]&&!vis[j]){
                minp=j;
                minw=minn[j];
            }
        }
        vis[minp]=true;
        sumv+=minw;
        for(int j=1;j<=n;j++){
            minn[j]=min(minn[j],g[minp][j]);
        }
    }
}
int main(){
    scanf("%d",&T);
    for(int i=1;i<=T;i++){
        Clear();
        init();
        prim();
        printf("%lld\n",sumv);
    }
    return 0;
}

转载于:https://www.cnblogs.com/virtual-north-Illya/p/10045386.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值