1.分考场(17年国赛——3月25日)
思路:
回溯法深度搜索解空间(dfs)
M是存放关系的矩阵;
room是考场的关系矩阵;
对于当前问题dfs(x,kc);
即是第x个考生,kc个考场;从第一个考场开始找,
该考场没人,直接入考场;
该考场有人,遍历这些人,如果没有认识的入考场;
如果有认识的就找下一个考场;一但入了考场,就递归dfs找下一规模问题,知道找到一个解,和当前值比较,如果更优就更新;
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<vector>
#define ll long long
#define maxn 110
using namespace std;
bool f[maxn][maxn];
int n,m;
int ans=500;
int k_count;
int k_num[maxn];
int k_i[maxn][maxn];
void dfs(int pos,int last)
{
if(last>=ans)
return;
if(pos==n+1)
{
if(last<ans)
{
ans=last;
}
return;
}
for(int i=1;i<=last;i++)
{
bool flag=true;
for(int j=1;j<=k_num[i];j++)
{
if(f[pos][k_i[i][j]])
{
flag=false;
break;
}
}
if(flag)
{
k_i[i][++k_num[i]]=pos;
dfs(pos+1,last);
--k_num[i];
}
}
k_num[last+1]=1;
k_i[last+1][1]=pos;
dfs(pos+1,last+1);
k_num[last+1]=0;
}
int main()
{
cin>>n>>m;
int temp1,temp2;
for(int i=0;i<m;i++)
{
cin>>temp1>>temp2;
f[temp1][temp2]=f[temp2][temp1]=true;
}
dfs(1,1);
cout<<ans<<endl;
}
2. 四平方和(16年省赛——3月11日)
暴力才能AC
#include <bits/stdc++.h>
using namespace std;
int main() // 暴力。
{
int n, a, b, c, d, flag = 0;
while (cin >> n){
flag = 0;
int temp = sqrt(n) + 1;
for (a = 0; a <= temp; a++) {
if (a*a > n) break;
for (b = a; b <= temp; b++) { //
if (a*a + b*b > n) break;
for (c = b; c <= temp; c++) {
if (a*a + b*b + c*c > n) break;
for (d = c; d <= temp; d++) {
if (a*a + b*b + c*c + d*d == n) {
cout << a << ' ' << b << ' ' << c << ' ' << d << endl;
flag = 1;
break;
}
if (a*a + b*b + c*c + d*d > n) break;
}
if (flag) break;
}
if (flag) break;
}
if (flag) break;
}
}
}
3. 最少砝码(21年省赛——3月8日)
本题为二刷题,思路与第一次做一样,直接就上代码了
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n;
cin>>n;
int ans;
for(ans=1;;ans++)
{
if(pow(3,ans)-1>=2*n)break;
}
cout<<ans<<endl;
return 0;
}
4.k倍区间(17年省赛——3月16日)
前和 每次相加 然后在数组加上k的余数
#include<iostream>
using namespace std;
const int N =100010;
int n,k;
long long s[N],cnt[N];
long long res;
int main()
{
cnt[0] = 1;
cin >> n >> k;
for(int i = 1; i <= n; i ++ )
{
cin >> s[i];
s[i] += s[i - 1];
res += cnt[s[i] % k];
cnt[s[i] % k]++ ;
}
cout << res;
return 0;
}
5. 七段码(20年省赛)
#include <iostream>
using namespace std;
const int N = 10;
int ans;
int p[N];
bool st[N];
int e[N][N];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void dfs(int u)
{
if(u == 8)
{
for (int i = 1; i <= 7; i ++) p[i] = i;
for (int i = 1; i <= 7; i ++)
for (int j = 1; j <= 7; j ++)
if(e[i][j] && st[i] && st[j])
p[find(i)] = find(j);
int cnt = 0;
for (int i = 1; i <= 7; i ++)
if(st[i] && p[i] == i)
cnt ++;
if(cnt == 1) ans ++;
return;
}
st[u] = 1; // 打开第 u 个二极管
dfs(u + 1);
st[u] = 0; // 关闭第 u 个二极管
dfs(u + 1);
}
int main()
{
e[1][2] = e[1][6] = 1;
e[2][1] = e[2][7] = e[2][3] = 1;
e[3][2] = e[3][7] = e[3][4] = 1;
e[4][3] = e[4][5] = 1;
e[5][4] = e[5][7] = e[5][6] = 1;
e[6][1] = e[6][7] = e[6][5] = 1;
e[7][2] = e[7][3] = e[7][5] = e[7][6] = 1;
dfs(1);
cout << ans << endl;
return 0;
}
6. 区间移位(17年国赛)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, a, b;
struct node
{
int a, b;
};
vector<node> q;
bool cmp(node x, node y)
{
return x.b < y.b;
}
bool check(int m) //最大移动距离m,判断是否能覆盖整个区间;
{
vector<node> tmp(q); //建立一个q的复制tmp;
int k = 0; //最大能覆盖的区间右端点;
while(true)
{
bool flag = false;
for(int i = 0; i < tmp.size(); i++)
{
node now = tmp[i];
int ta = now.a;
int tb = now.b;
if(ta-m <= k && tb+m >= k) //k在区间[ta-x, tb+x]内,不在则m太小;
{
flag = true;
int len = tb - ta; //当前这个区间的长度;
if(ta+m >= k)
k = k + len; //k最大能多覆盖到k+len的范围;
//ta+x>=k,那么只需要让区间的左端点移动到k处,右端点此时在k+len处;
else
k = tb + m; //ta+x<k,k最大能多覆盖到该区间的右端点,再多走m的长度;
tmp.erase(tmp.begin()+i); //将选择的区间去掉,避免重复判断;
break;
}
}
if(k >= 20000 || !flag) break;
//如果找不到可以覆盖的区间,或者k已经达到20000了,就可以结束检验了;
}
return k >= 20000;
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a >> b;
a *= 2; //答案存在0.5,可以将所有东西扩大两倍,最后再除2就可以了;
b *= 2;
q.push_back({a, b});
}
sort(q.begin(), q.end(), cmp); //按右端点从大到小排序;
int l = 0, r = 20000; //因为扩大了2倍,枚举答案范围也大了2倍;
while(l <= r) //二分答案:枚举最大移动的距离,使最大移动距离最小;
{
int mid = (l+r)/2;
if(check(mid))
r = mid - 1;
else
l = mid + 1;
}
double ans = (r + 1) / 2.0;
cout << ans << endl;
return 0;
}
7.数正方形(19国赛)
思路:只要当n=4时答案是20,任何人都可以过
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
cout<<20<<endl;
return 0;
}