机房水题欢乐赛 2016-04-16

暨市(校)队选拔赛

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.

T4:seq

http://blog.csdn.net/huanghongxun/article/details/50686941

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值