补题报告3

CSP-J模拟三补题报告(2024.10.5)
一、得分情况
T1[IP地址(ip)】:100分
T2[是否同构(same)】:0分
T3[箱子(box)】:0分
T4[社恐的聚会(party)】:10分
总分:110分
————————————————————————————————————————————————————————————————————————————————————————————————————————————————
二、比赛概况
T1:AC
T2:爆了
T3:纯以合并果子的思路做,有问题
T4:???
————————————————————————————————————————————————————————————————————————————————————————————————————————————————
三、题目分析
1.题目大意
T1[IP地址(ip)】Map映射查找
T2[是否同构(same)】在A数组中寻找B【1】的位置,然后将A数组中对应向后的位置与其交换。
T3[箱子(box)】有很多次合并机会,使合并小号的体力值尽量小
T4[社恐的聚会(party)】将N个人分在两张桌子,使人最多的桌子上入座的人最少。
————————————————————————————————————————————————————————————————————————————————————————————————————————————————
2.考试的思路
T1:AC
T2:枚举,爆了
T3:合并果子,没有在意最多为M堆,以为必须得合并M堆,思路就错了
T4:???
————————————————————————————————————————————————————————————————————————————————————————————————————————————————
3.解题思路
T1:Map映射容器的使用,定义两个string在里面,把两个string存进去之后只要输入另一个string就可以映射出它的值了
T2:先在A数组中找到B【1】的位置K,然后将从A【K】到A【N】的区间和A【1】A【I-K+1】进行交换再判断如果相同则输出”Yes“,否则输出”No“
T3:使用最小优先队列,使其合并前先排序。如果不能刚好合成,应先将小的不足数的合成。进行合并时,依次取出队列顶部元素,然后相加压进队列,重复此操作,直至队列元素数量为一,然后输出q.top();
T4: 肯定要将每一个人分到两桌中的一桌。
在操作每一个人的时候,不看他和谁认识,看他和谁不认识,将和他不认识的人分到另一桌就可以了。
利用A,B队列,每次将一个人出队,将和他不认识的人全部入另一个队列队,直到队列为空。
最后,还有一些人去哪里都行,将他们平均分配即可。
判断NO的方法,将A队中的每一个人两两判断是否认识。B队列同理
四、AC代码(程序输入输出)
T1:##########################################################################################################################################################################################

#include <bits/stdc++.h>
using namespace std;
map<string,string> mp;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
string s1,s2;
cin>>s1>>s2;
mp[s2]=s1;
}
int m;
cin>>m;
while(m–)
{
string s1;
cin>>s1;
cout<<mp[s1]<<“\n”;
}
return 0;
}
T2:##########################################################################################################################################################################################
#include
using namespace std;
int a[1000005],b[1000005],n,m=0,k;
void solve()
{
scanf(“%d”,&n);
for(int i=1;i<=n;i++) scanf(“%d”,&a[i]);
for(int i=1;i<=n;i++) scanf(“%d”,&b[i]);
int pos=0;
for(int i=1;i<=n;i++)
{
if(a[i]==b[1])
{
pos=i;
break;
}
}
for(int i=pos;i<=n;i++)
{
swap(a[i],a[i-pos+1]);
}
for(int i=1;i<=n;i++)
{
if(a[i]!=b[i])
{
printf(“No\n”);
return ;
}
}
printf(“Yes\n”);
}
int main()
{
int u;
scanf(“%d”,&u);
while(u–)
{
solve();

}
return 0;

}
T3:##########################################################################################################################################################################################
#include
#include
#define N 100005
#define ll long long
using namespace std;
ll n,m,x;
priority_queue<ll,vector,greater >q;
int main()
{
cin>>n>>m;

for(int i=1;i<=n;i++)
{
    cin>>x;
    q.push(x);
}
ll ans=0;
if((n-1)%(m-1)!=0)
{
   ll k=(n-1)%(m-1),sum=0;
    for(int i=1;i<=k+1;i++)
    {
        sum+=q.top();
        q.pop();
    }
    q.push(sum);
    ans+=sum;
}
while(q.size()>=m)
{
    ll sum=0;
    for(int i=1;i<=m;i++)
    {
        sum+=q.top();
        q.pop();
    }
    ans+=sum;
    q.push(sum);
}
cout<<ans;

}
T4:###########################################################################################################################################################################################
#include<bits/stdc++.h>
#define CLOSE std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
#define ll long long
#define N 1000005
#define M 100005
using namespace std;
/*
解题思路:
肯定要将每一个人分到两桌中的一桌。
在操作每一个人的时候,不看他和谁认识,看他和谁不认识,将和他不认识的人分到另一桌就可以了。
利用A,B队列,每次将一个人出队,将和他不认识的人全部入另一个队列队,直到队列为空。
最后,还有一些人去哪里都行,将他们平均分配即可。
判断NO的方法,将A队中的每一个人两两判断是否认识。B队列同理

*/
int n,mp[550][550],vis[550];
queue q1,q2;
int a[550],b[550],cnt1 = 0,cnt2 = 0;
struct node{
int d,id;
}ind[550];
bool cmp(node a,node b){
return a.d < b.d;
}
void bfs(){
//q1的每一个人,不认识的放在q2; q2的每一个人,不认识的放在q1,直到队列为空
while(!q1.empty() || !q2.empty()){
if(!q1.empty()){
int x = q1.front();
q1.pop();
for(int i = 1; i <= n; i++){
if(mp[x][i] == 0 && !vis[i] && i != x){//x不认识i,并且没有如果队,放到另一桌
q2.push(i);
vis[i] = 2;
b[++cnt2] = i;
}
}
}
if(!q2.empty()){
int x = q2.front();
q2.pop();
for(int i = 1; i <= n; i++){
if(mp[x][i] == 0 && !vis[i] && i != x){
q1.push(i);
vis[i] = 1;
a[++cnt1] = i;
}
}
}
}
}
bool check(int cnt1,int cnt2){//判断是否满足条件
//看看是否存在某一桌,有不认识的人
for(int i = 1; i <= cnt1; i++){
for(int j = i + 1; j <= cnt1; j++){
if(mp[a[i]][a[j]] == 0 || mp[a[j]][a[i]] == 0){
// cout << “No\n”;
return 0;
}
}
}
for(int i = 1; i <= cnt2; i++){
for(int j = i + 1; j <= cnt2; j++){
if(mp[b[i]][b[j]] == 0 || mp[b[j]][b[i]] == 0){
// cout << “No\n”;
return 0;
}
}
}
return 1;
}
//处理每一个漏网之鱼
int flag = 0,yu[550],k = 0;
int ans = 1e9;
void dfs(int x,int cnt1,int cnt2){//正在处理第x个漏网之鱼
if(ans <= max(cnt1,cnt2))
return ;
if(x == k + 1){
if(check(cnt1,cnt2)){
flag = 1;
ans = min(ans,max(cnt1,cnt2));
return ;
}
return ;
}
//尝试将第x个人放入到a桌,同时和之前的人看看认不认识
int flag = 1;
for(int i = 1; i <= cnt1; i++){
if(mp[yu[x]][a[i]] == 0 || mp[a[i]][yu[x]] == 0){
flag = 0;
break;
}
}
if(flag){
a[cnt1+1] = yu[x];
vis[yu[x]] = 1;
dfs(x + 1,cnt1 + 1,cnt2);
vis[yu[x]] = 0;
}

//尝试将第x个人放入到b桌
flag = 1;
for(int i = 1; i <= cnt2; i++){
    if(mp[yu[x]][b[i]] == 0 || mp[b[i]][yu[x]] == 0){
        flag = 0;
        break;
    }
}
if(flag){
    b[cnt2+1] = yu[x];
    vis[yu[x]] = 2;
    dfs(x + 1,cnt1,cnt2 + 1);
    vis[yu[x]] = 0;
}

}
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cin >> mp[i][j];
if(mp[i][j])
ind[i].d++;
}
ind[i].id = i;
}
//安排随意
sort(ind + 1,ind + n + 1,cmp);
if(ind[1].d != n - 1){//先放第一个人,随便入座
q1.push(ind[1].id);
vis[ind[1].id] = 1;
a[++cnt1] = ind[1].id;
}else{//所有人相互认识
cout << “Yes\n”;
cout << (n + 1) / 2;
return 0;
}
bfs();
for(int i = 1; i <= n; i++){
if(!vis[i]){
yu[++k] = i;
}
}
dfs(1,cnt1,cnt2);
if(flag == 1){
cout << “Yes\n” << ans;
}else{
cout << “No\n”;
}
return 0;
}

5.反思
1)仔细观察数据规模,防止 () 爆炸!
2)审题要认真仔细
3)不会的就打暴力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值