暨市(校)队选拔赛
T1:Rob
已知将一个大矩形切割成多个小矩形,每个矩形涂一种颜色,要求涂色的时候与其上边界相邻的矩形先涂了,该矩形才能涂,而且一次涂只能涂同一种颜色,问最少更换多少次颜色才能完成?
分成最多16个小矩形,棋盘最大100*100。
输入样例
7
0 0 2 2 1
0 2 1 6 2
2 0 4 2 1
1 2 4 3 2
1 3 3 6 1
4 0 6 3 1
3 3 6 6 2
输出样例
3
样例解释
先涂2号和4号,然后再涂1、3、4、5号,然后再涂7号。
题解
暴力搜索即可
一开始肉眼查错查了2、3个错误好虚。。不过幸好A了。比较懒这里都用STL了。。
程序
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
#define test printf("FUCK");
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f, mod = 1000000007;
int read() {
int s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
int qpow(int a, int b) {
int s = 1;
for (; b; b /= 2, a = a * a % mod)
if (b & 1) s = s * a % mod;
return s;
}
namespace Solve {
const int N = 32;
int vis[N], c[N], ind = 0, draw = 0, n, in[N], ans = inf;
vector<int> g[N], f[N], has[N], rein[N];
map<int, int> id;
queue<int> q;
void bfs(int x, int t) {
int u, i, p = c[x];
q.push(x);
while (!q.empty()) {
u = q.front(); q.pop(); vis[u] = 1; f[t].push_back(u);
rep(i,0,g[u].size()) if (!vis[g[u][i]]) {
--in[g[u][i]]; rein[t].push_back(g[u][i]);
if (c[g[u][i]] == p && !in[g[u][i]]) {
q.push(g[u][i]);
}
}
}
}
void dfs(int dep) {
int i, j;
if (draw == n) ans = min(ans, dep);
else if (dep < ans)
FOR(i,1,ind) {
bool flag = 0;
rep(j,0,has[i].size())
if (!in[has[i][j]] && !vis[has[i][j]]) {
flag = 1; break;
}
if (flag) {
rein[dep].clear(); f[dep].clear();
rep(j,0,has[i].size())
if (!in[has[i][j]] && !vis[has[i][j]])
bfs(has[i][j], dep);
draw += f[dep].size();
dfs(dep + 1);
draw -= f[dep].size();
rep(j,0,f[dep].size()) vis[f[dep][j]] = 0;
rep(j,0,rein[dep].size()) ++in[rein[dep][j]];
}
}
}
int x1[N], x2[N], y1[N], y2[N];
void solve() {
int i, j;
n = read();
FOR(i,1,n) {
scanf("%d%d%d%d%d", &y1[i], &x1[i], &y2[i], &x2[i], &c[i]);
if (!id.count(c[i]))
id[c[i]] = ++ind;
c[i] = id[c[i]];
has[c[i]].push_back(i);
}
FOR(i,1,n) FOR(j,1,n) if (y2[i] == y1[j])
if (x1[i] >= x1[j] && x1[i] <= x2[j] ||
x2[i] >= x1[j] && x2[i] <= x2[j]) {
g[i].push_back(j); ++in[j];
}
dfs(0);
printf("%d", ans);
}
}
#define FILENAME "rob"
int main() {
freopen(FILENAME".in","r",stdin);
freopen(FILENAME".out","w",stdout);
Solve::solve();
return 0;
}
T2:打保龄球
题目好复杂。。不记得题了。
每轮有2次投球机会,如果第一次击完10个柱子,那么接下来2次投球得的分和本次的得分10分就算作本轮得分,如果第二次才击完10个柱子,那么接下来1次投球得的分和本轮总的10分就算作本轮得分,如果两次机会没能击完10个柱子,击去的柱子数为本轮得分。
某轮第二次机会不会重新将柱子恢复到10个,接着打上一个机会留下的柱子。
如果第10轮击完了柱子可增加第11或12轮。
输入样例
/ / / / 54 36 25 25 1/ 28
每项为1轮的得分情况,/表示投完。数字+/表示第1次机会未投完,得分为数字,第2次机会投完。数字+数字表示第1、2次机会均未投完,得分为对应数字。
至于数字+数字情况和为10,只能说明数据不严谨。。就当未投完好了。。
输出样例
30 30 25 19 9 9 7 7 12 10
158
输出每轮得分和总分。
样例解释
令
ok(i,j)
表示第i轮第j次投完。
ok(1,1) && ok(2,1) && ok(3,1),因此第1轮10+10+10=30分。
同理第2轮30分。
ok(3,1) && ok(4,1) && !ok(5),因此第3轮10+10+5=25分
ok(4,1) && !ok(5),因此第4轮得分10+5+4=19分
第5轮得分5+4=9分(由于未击完,因此不算下一轮的得分)
同理第6、7、8、10轮。
ok(9,2),因此第9轮得分10(1+9)+2=12分。
程序
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
#define test printf("FUCK");
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f, mod = 1000000007;
int read() {
int s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
int qpow(int a, int b) {
int s = 1;
for (; b; b /= 2, a = a * a % mod)
if (b & 1) s = s * a % mod;
return s;
}
namespace Solve {
const int N = 32, M = N * 8;
char sit[N][8];
char s[M];
int c[M], t[M], k[M];
void solve() {
int n = 0, i, j, p = 0, mark = 0, ans = 0, l, r, out = 0;
while (scanf("%s", sit[n]) != EOF) ++n;
rep(i,0,n) {
s[++p] = sit[i][0]; t[p] = 0;
if (s[p] != '/') {
k[p] = s[p] - '0'; c[p] = -1;
s[++p] = sit[i][1]; t[p] = 1;
if (s[p] == '/')
c[p] = 1, k[p] = 10 - k[p - 1];
else
c[p] = 0, k[p] = s[p] - '0';
} else {
k[p] = 10; c[p] = 2;
}
}
FOR(i,1,p) {
if (c[i] >= 0) l = 0, r = c[i]; // If the second chance or get full mark in a round(not only one chance)
else ++i, l = -1, r = c[i]; // If does not get full mark in a round, first chance
FOR(j,l,r) mark += k[i + j];
if (t[i] >= t[i + 1]) {
ans += mark;
printf("%d ", mark); ++out;
if (out >= 10) break;
mark = 0;
}
}
printf("\n%d", ans);
}
}
#define FILENAME "ball"
int main() {
freopen(FILENAME".in","r",stdin);
freopen(FILENAME".out","w",stdout);
Solve::solve();
return 0;
}
T3:切割块问题
将一个矩阵切割成几种零件:一种是1*3的矩形,一种是2*2的L形,可以旋转,问有多少种方案?
如4*6的矩阵方案数为248。
矩阵规模最大8*8。
结果这道题打样例+无解有50分,没骗分好亏QAQ。不过也就校赛会出这么水的数据了。
暴力解决。。。。。。。
program LT11_14;
const
filein='cut.in'; fileout='cut.out';
dy:array[1..6,1..3]of integer
=((0,1,2),(0,0,0),(0,0,1),(0,1,1),(0,0,1),(0,0,-1));
dx:array[1..6,1..3]of integer
=((0,0,0),(0,1,2),(0,1,0),(0,0,1),(0,1,1),(0,1,1));
var
map,b:array[1..20,1..20] of integer;
c:array[1..100000,1..3] of integer;
n,m,t,s:longint; tt:boolean;
fin,fout:text;
procedure init;
begin
fillchar(map,sizeof(map),0); fillchar(c,sizeof(c),0);
assign(fin,filein);reset(fin); readln(fin,n,m);
assign(fout,fileout);rewrite(fout);
end;
procedure clear; {清标记过程}
var x,y,k,i,x1,y1:integer;
begin
y1:=c[t,1];x1:=c[t,2];k:=c[t,3];{取出第t步的坐标值(y,x),零件号k}
for i:=1 to 3 do {清除第t步放k零件的标记}
begin y:=y1+dy[k,i]; x:=x1+dx[k,i]; map[y,x]:=0; end;
end;
procedure target(var tt:boolean);{判断是否完全切割完,返回为true表示全切割完}
var i,j,p:integer;
begin
p:=0;tt:=false;
for i:=1 to n do
for j:=1 to m do if map[i,j]=0 then inc(p);
if p=0 then tt:=true;
end;
procedure dfs; {深度搜索过程}
var i,j,k,bj,L,h,x,y,x1,y1,p:integer;
bb,bd:boolean;
begin
bb:=true;t:=0;s:=0;
while bb do
begin
bj:=0;
for i:=1 to n do {从n*m的方形阵列中,找可以放置零件的位置}
begin
for j:=1 to m do
if map[i,j]=0 then begin h:=i;L:=j;bj:=1;break;end;
if bj=1 then break;
end; {坐标(h,L)就是可以放置零件的位置,h为行,L为列}
inc(t);b[h,L]:=0;bd:=true;
while bd do
begin
inc(b[h,L]);k:=b[h,L]; {在(h,L)位置选择零件号}
if k<7 then {零件号没有超过限定值}
begin
x1:=L;y1:=h; {当前坐标点为(y1,x1)}
for i:=1 to 3 do {从当前坐标点放k零件,计算坐标}
begin
y:=y1+dy[k,i];x:=x1+dx[k,i];p:=0;
if (y>0)and(y<=n)and(x>0)and(x<=m)and(map[y,x]=0)then
else begin p:=1;break;end;
end;
if p=0 then {p=0成立说明从当前点可以放零件k}
begin
x1:=L;y1:=h;c[t,1]:=h;c[t,2]:=L;c[t,3]:=k; {保存第t步放零件的信息}
for i:=1 to 3 do {标记所放的零件号k}
begin
y:=y1+dy[k,i];x:=x1+dx[k,i]; map[y,x]:=k;
end;
target(tt); {判断是否完全切割完}
if tt then begin inc(s);clear;end {累计方案数并清第t步所放零件标记}
else bd:=false;
end;
end
else begin
t:=t-1; {并往回退一步}
if t<1 then begin bb:=false;bd:=bb;end {当t<1表示结束}
else begin clear; h:=c[t,1];L:=c[t,2]; end;
{清退回到第t的零件标记并取出当前位置的坐标(h,L)}
end;
end;
end;
end;
begin
init; dfs;
if s>0 then writeln(fout,s) else writeln(fout,'NO');
close(fout);
end.