代码改变世界

NOI导刊2008第十套trans 结题报告

2012-10-11 19:08  kliner  阅读(318)  评论(1编辑  收藏  举报

  题目大意:对于由某个从A到Z所有字符不重不漏构成的字符串,如HRSLCZDKIYXUNOMTGVJEFAWBPQ,这表示把'A'置换为'H',把'B'置换为'R'......把'Z'置换为'Q'。现在我们把这个置换进行两次从而得到一个新的置换。你的任务是判断一个字串是否是由一个置换操作两次得到的新的置换。

  输入:一个由'A'到'Z'不重不漏组成的字符串。

  输出:若这个字串是否是由一个置换操作两次得到的新的置换,输出"Yes",反之,输出"No"。

  题解:一开始我看到这道题一点思路都找不着,甚至想用暴搜直接解决它,写到一半太复杂都写不动了...-_-。最后看到题解才恍然大悟。

由于一个字母总是由另一个字母置换而来,而又总是可以置换为另一个字符(包括它本身),所以我们可以将'A'—'Z'看作26个顶点,有从顶点i到顶点j的有向边当且仅当字母i置换为字母j。这样我们会得到几个环,现在我们看看将一个置换进行两次的后果:若该环为奇环,则该环进行两次置换后大小不变,只是一个顶点指向它的下下个顶点。若该环为偶环,则置换两次后它会分裂成两个顶点数相等的小环。那么显然置换两次后形成的偶环一定由更大的偶环分解而来,那么顶点数相同的偶环数目为偶数则有解,反之则无解。

  下面贴出代码:

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4 ifstream fin("trans.in");
 5 ofstream fout("trans.out");
 6 char end[30];
 7 //bool matrix[30][30];
 8 int evencir,oddcir[30];
 9 int istested[30];
10 int tested[30];
11 int main()
12 {
13     int i=0;
14     for(i=1;i<=26;i++)
15     {
16         fin>>end[i];
17         if(tested[end[i]-'A'+1])
18         {
19             fout<<"No"<<endl;
20             return 0;
21         }
22         tested[end[i]-'A'+1]=true;
23     }
24     int flag=0;
25     int now=0;
26     while(1)
27     {
28         if(flag==0)
29         {
30             for(i=1;i<=26;i++)
31             {
32                 if(!istested[i])
33                 {
34                     break;
35                 }
36             }
37             if(i==27)
38                 break;
39             else
40             {
41                 flag++;
42                 istested[i]=true;
43                 //matrix[i][end[i]-'A'+1]=true;
44                 now=end[i]-'A'+1;
45             }
46         }
47         else
48         {
49             if(istested[now])
50             {
51                 if(flag%2==1)
52                     evencir++;
53                 else
54                     oddcir[flag]++;
55                 flag=0;
56             }
57             else
58             {
59                 istested[now]=true;
60                 now=end[now]-'A'+1;
61                 flag++;
62             }
63         }
64     }
65     for(i=1;i<=26;i++)
66     {
67         if(oddcir[i]%2!=0)
68         {
69             break;
70         }
71     }
72     if(i<=26)
73         fout<<"No"<<endl;
74     else
75         fout<<"Yes"<<endl;
76     return 0;
77

这道题充分说明考虑一个问题时应从多个不同角度考虑,结合多种理论发现其特点再求解是一个重要手段。