【usaco 2013 Mar Bronze】

第一题:

题目:
农夫约翰有N只奶头,这N只奶牛分别属于三个种类:A,B,C。但是不幸的是,约翰忘记了每只奶牛分别属于哪个种类了。他仅仅只记得的K个奶牛之间的关系。例如,他记得奶牛1和奶牛2是同一种类,或者奶牛1和奶牛5是不同种类的。
问题描述:
给定这K个关系,请帮助约翰计算这N只奶牛可能的种类分布情况共有多少种。(当K个关系本身就是矛盾的时候,答案是0)。
输入
第一行是两个正整数N和K,表示奶牛的数量和关系的数量。
接下来K行,每行是一个奶牛种类的关系,“S x y”表示奶牛x和奶牛y是相同种类的,“D x y”表示奶牛x和奶牛y是不同种类的。


输出
输出满足关系条件的奶牛种类分布情况共有多少种。


样例输入
4 2 
S 1 2
D 1 3

样例输出
18

数据范围限制
数据范围:1<=N<=15,1<=K<=50。

提示
说明:样例中,对于奶牛1、奶牛2、奶牛3共有6种情况分别是:AAB,AAC,BBA,BBC,CCA,CCB。奶牛4有3种可能,所以最终总的可能性是18种。


这道题其实就是普通的dfs,判断条件是否成立,然后当dfs完之后需要把没有条件的奶牛*3,就等于答案了——题目中说的自相矛盾其实可以不用理会,因为当这n个条件自相矛盾时,ans dfs的时候一定是0,0再乘3也还是0.

代码:

var
        i,n,k,x,y,tot:longint;
        a,b:array[0..15] of longint;
        bz:array[1..15] of boolean;
        f:array[1..15,1..15] of 0..2;
        ch,c:char;
function pd(k,num,kind:longint):boolean;
var
        i:longint;
begin
        pd:=true;
        for i:=1 to k do
                if ((f[b[i],num]=1) and (kind<>a[i])) or ((f[b[i],num]=2) and (kind=a[i])) then exit(false);
end;

procedure dfs(t:longint);
var
        i:longint;
begin
        if t>b[0] then
        begin
                inc(tot);
                exit;
        end;

        for i:=1 to 3 do
                if pd(t-1,b[t],i) then
                begin
                        inc(a[0]);
                        a[a[0]]:=i;
                        dfs(t+1);
                        a[a[0]]:=0;
                        dec(a[0]);
                end;
end;

begin
        assign(input,'assign.in'); reset(input);
        assign(output,'assign.out'); rewrite(output);

        readln(n,k);
        fillchar(bz,sizeof(bz),true);
        for i:=1 to k do
        begin
                readln(ch,c,x,c,y);
                if bz[x] then
                begin
                        bz[x]:=false;
                        inc(b[0]);
                        b[b[0]]:=x;
                end;
                if bz[y] then
                begin
                        bz[y]:=false;
                        inc(b[0]);
                        b[b[0]]:=y;
                end;
                if ch='S' then
                begin
                        f[x,y]:=1; f[y,x]:=1;
                end
                else
                begin
                        f[x,y]:=2; f[y,x]:=2;
                end;
        end;

        dfs(1);

        for i:=1 to n-b[0] do
                tot:=tot*3;
        writeln(tot);

        close(input); close(output);
end.


第二题:

题目:
   农夫约翰的奶牛通常是按1到N进行编号的,奶牛们相互之间有一种特殊的信息传输方式。在信息传递的过程中,每只奶牛的信息最多传递到另一只奶牛,对于奶牛i,Fi表示他要传递信息的那只奶牛的编号,这里i和Fi肯定是不同的,如果Fi是0,则表示奶牛i没有要传递信息给其他的奶牛。
   不幸的是,奶牛们知道了这种传递信息的方式可能会导致一个死循环。如果一个奶牛传递信息最终会导致一个死循环,那么我们就说这只奶牛在死循环里面。
问题描述:
请帮助奶牛们计算有多少头奶牛没有在死循环里面。

输入
第一行一个正整数N,表示奶牛的数量。
接下来第2行到N+1行,每行一个非负整数,对于第i+1行上的数,表示奶牛i要把信息传递过去的奶牛的编号,如果是0则表示这头奶牛不需要传递信息。


输出
输出不在死循环里面的奶牛的数量。


样例输入
5

0
4
1
5
4

样例输出
2

数据范围限制
数据范围:1<=N<=1000。

提示
说明:样例中,奶牛1不在死循环中因为他不传递信息,奶牛3也不在死循环中是因为他传递信息给奶牛1。其他的奶牛全部都在死循环中,所以样例的答案是2。


其实这道题就只要把他传递模拟一下即可,因为如果传递n次之后还没有传递0就可以证明一定进入死循环了,然后退出循环即可。

代码:

var
        n,i,x,j,k,TOT,len:longint;
        a:array[1..1000] of longint;
        b:array[1..2000] of record
                tot,num:longint;
        end;
        bz:boolean;
begin
        assign(input,'relay.in'); reset(input);
        assign(output,'relay.out'); rewrite(output);

        readln(n);
        for i:=1 to n do
                readln(a[i]);
        for i:=1 to n do
        begin
                len:=0;
                inc(len);
                b[len].tot:=a[i];
                b[len].num:=i;
                x:=b[len].num;
                if a[x]=0 then
                begin
                        inc(tot);
                        continue;
                end;
                for j:=1 to n do
                begin
                        x:=a[b[len].num];
                        inc(len);
                        b[len].num:=x;
                        b[len].tot:=a[x];
                        if a[x]=0 then
                        begin
                                inc(tot);
                                break;
                        end;
                end;

        end;

        writeln(tot);

        close(input); close(output);
end.


第三题:

题目:
     农夫约翰在他的农田上了放置了N个干草堆,如果我们考虑农田是100*100的方格,每个干草堆占一个小方格(没有两个干草堆占据同一个小方格)。
     约翰发现他的所有干草堆组成了一个连通分量,即从任意一个干草堆出发,都可以通过若干次向上或向下或向左或向右的移动到相邻的有干草堆的小方格而达到任意一个其他的干草堆。这里,干草堆的堆放可能会出现“洞”,“洞”是一块空地,但是都被干草堆所包围。
问题描述:
     请帮助约翰计算所有被干草堆占领的小方格所组成的图形的周长。注意,“洞”是不计入周长的范围内的。
输入
第一行一个正整数N,表示干草堆的个数。
接下来N行,每行两个整数,表示每个干草堆放置的位置。
输出
输出周长。


样例输入
8

5 3

5 4

8 4

5 5

6 3

7 3

7 4 

6 5

样例输出
14

数据范围限制
数据范围:1<=N<=10000。


这道题目——把能搜索到的且四周有小草堆的地方,方案数+1即可。

var
        n,i,x,y,tot:longint;
        bZ,ff:array[-1..102,-1..102] of boolean;
procedure dfs(x,y:longint);
begin
        if (x=-1) or (x=102) or (y=-1) or (y=102) then exit;
        if not bz[x-1,y] then inc(tot);
        if not bz[x,y-1] then inc(tot);
        if not bz[x+1,y] then inc(tot);
        if not bz[x,y+1] then inc(tot);

        if bz[x-1,y] and ff[x-1,y] then
        begin
                ff[x-1,y]:=false;
                dfs(x-1,y);
        end;
        if bz[x,y-1] and ff[x,y-1] then
        begin
                ff[x,y-1]:=false;
                dfs(x,y-1);
        end;
        if bz[x+1,y] and ff[x+1,y] then
        begin
                ff[x+1,y]:=false;
                dfs(x+1,y);
        end;
        if bz[x,y+1] and ff[x,y+1] then
        begin
                ff[x,y+1]:=false;
                dfs(x,y+1);
        end;
end;

begin
        assign(input,'Perimeter.in'); reset(input);
        assign(output,'Perimeter.out'); rewrite(output);

        readln(n);
        fillchar(bz,sizeof(bz),true);
        for i:=1 to n do
        begin
                readln(x,y);
                bz[x,y]:=false;
        end;

        fillchar(ff,sizeof(ff),true);
        dfs(0,0);
        writeln(tot);

        close(input); close(output);
end.


第四题:

题目:
     奶牛贝里斯最近逃离了农夫约翰的农场躲在草丛里。于是,农夫约翰试图去找回他的奶牛。不幸的是,这些高高的草丛挡住了约翰的视线。现在,我们把这些草丛描述为一个长度为N的字符串,这个字符串只包含‘(’和‘)’这两种字符。例如,字符串:)((()())()) 。约翰知道贝里斯隐藏的前大腿很像连续的两个左括号((,隐藏的后大腿很像连续的两个右括号))。贝里斯的位置可以描述为:((的位置为X,))的位置为Y,并且X<Y。
问题描述:
     请帮助约翰计算贝里斯隐藏的地方有多少种可能。
输入
只有一行一个字符串。
输出
输出贝里斯所有可能位置的总数。


样例输入
)((()())())
样例输出
4
数据范围限制
1<=N<=50000。
提示
样例中,总共有四种可能性,如下所示:


这道题目非常简单,只用简单的模拟一下就行了:

var
        s:ansistring;
        i,j,n,lena,lenb,x,ans:longint;
        a,b:array[1..50000] of longint;
begin
        assign(input,'cowfind.in'); reset(input);
        assign(output,'cowfind.out'); rewrite(output);

        readln(s);
        for i:=1 to length(s) do
        begin
                if (s[i]='(') and (s[i+1]='(') then
                begin
                        inc(lena);
                        a[lena]:=i;
                end
                else
                if (s[i]=')') and (s[i+1]=')') then
                begin
                        inc(lenb);
                        b[lenb]:=i;
                end;
        end;
        x:=lena;
        for i:=lenb downto 1 do
        begin
                while b[i]<=a[x] do dec(x);
                inc(ans,x);
        end;
        writeln(ans);

        close(input); close(output);
end.




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值