ProblemG 加边
题目来源:ProblemG 加边
解题思路
签到题,这里首先要了解图的一些基本概念,度数是依附于该顶点的边的条数,我们可以记录每个点出现的次数,也就是每个点的度数,最后将这些度数为奇数的点相互连接添加一条边就可以使之都为偶数
代码实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define fi first
#define se second
int n,m,a,b;
map<int,int>mp;
void solve()
{
cin>>n>>m;
while(m--)
{
cin>>a>>b;
mp[a]++;
mp[b]++;
}
vector<int>v;
for(int i=1;i<=n;i++)
{
if(mp[i]%2!=0)
v.push_back(i);
}
cout<<v.size()/2<<endl;
for(int i=0;i<v.size();i+=2)
cout<<v[i]<<" "<<v[i+1]<<endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--)
solve();
return 0;
}
I - 王国------求策
题目来源:I - 王国------求策
解题思路:
仔细读题其实并不难,因为同一排不可直接到达,并且1~n中的每一城市只会和n+1 ~ 2n中的其中一个城市相冲。
因此,如果两个城市相冲一定不能到达。只要两个城市不相冲,那么就一定可以有路径到达。
当然需要排除特殊情况:
当n=2时,如果两个城市在同一排那么一定无法到达,但如果不同排,只要不相冲就一定能够到达。
并且题目中并没有说s不等于t,因此如果两个城市相同就一定能到达。
我们可以用map<pair<int,int>,int>mp来标记两个点是否相冲,因为两个城市互相相冲,所以反方向顺序也要标记。
记得map每次都要清空。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define fi first
#define se second
map<PII,int>mp;
void solve()
{
mp.clear();
int n,s,t,x;
cin>>n>>s>>t;
for(int i=1;i<=n;i++)
{
cin>>x;
mp[{x,i}]=mp[{i,x}]=1;
}
if(s==t)
{
cout<<"Yes"<<endl;
return ;
}
if(mp[{s,t}]==1)
{
cout<<"No"<<endl;
return ;
}
else
{
if(n>2)
{
cout<<"Yes"<<endl;
return ;
}
else if(n==1)
{
cout<<"No"<<endl;
return ;
}
else if(n==2)
{
if((s<=n&&t<=n)||(s>n&&t>n))
{
cout<<"No"<<endl;
return ;
}
else
{
cout<<"Yes"<<endl;
return ;
}
}
}
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _;
cin>>_;
while(_--)
solve();
return 0;
}
K - 微信小游戏
题目来源:K - 微信小游戏
解题思路
这是一到思维+模拟题,不难想到按最少的次数模拟,
首先,最终第一排一定包括每个颜色,这时候只需要找到每个颜色放哪里操作次数最少,当该颜色从第一行连续相同的方块最多时,计为MP[i],该颜色放在这里,对应的操作次数为n-mp[i],有的颜色第一行没有出现,那么操作次数就按n来计算。最后将总的操作次数加一起即可。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define fi first
#define se second
const int N=2005;
int n,m,a[N][N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cin>>a[i][j];
}
int ans=0;
map<int,int>mp;
for(int i=1;i<=m;i++)
{
ans=1;
for(int j=2;j<=n;j++)
{
if(a[j][i]==a[1][i])
ans++;
else
break;
}
mp[a[1][i]]=max(mp[a[1][i]],ans);
}
ans=0;
for(int i=1;i<=m;i++)
ans+=(n-mp[i]);
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--)
solve();
return 0;
}
F - 年少的誓约Ⅱ
题目来源:F - 年少的誓约Ⅱ
解题思路
可以把两个时间区间的每一时刻每一分钟遍历,并求出从这一时刻转到另两个时间的总角度,最终取最小即可,注意顺逆方向都要考虑。
代码实现
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fi first
#define se second
const int N = 1e6+5;
// 计算时针转动的角度(从0点0分开始)
double ho(int h, int m)
{
return (h * 30 + m * 0.5);
}
// 计算分针转动的角度(从0点0分开始)
double mi(int m)
{
return (m * 6);
}
void solve()
{
int x0, y0, x1, y1, x2, y2;
cin >> x0 >> y0 >> x1 >> y1 >> x2 >> y2;
double minn = 1e9;
int besth = -1, bestm = -1;// 遍历起始时间到结束时间的所有时刻
for (int h = x1; h <= x2; h++)
{
int sm = (h == x1) ? y1 : 0;
int em = (h == x2) ? y2 : 59;
for (int m = sm; m <= em; m++)
{
double h0 = ho(x0, y0);
double h1 = ho(h, m);
double m0 = mi(y0);
double m1 = mi(m);// 计算时针和分针需要转动的角度(考虑顺时针和逆时针的最小角度)
double ha = min(fabs(h1 - h0), 360 - fabs(h1 - h0));
double ma = min(fabs(m1 - m0), 360 - fabs(m1 - m0));
double cost = ha + ma;// 如果代价更小或者代价相同但时间更早,更新最佳时间
if (cost < minn || (cost == minn && (h < besth || (h == besth && m < bestm))))
{
minn = cost;
besth = h;
bestm = m;
}
}
}
cout << besth << " " << bestm << endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
cin >> t;
while(t--) solve();
return 0;
}
完结~太菜了只会这些!