SRM 441(1-250pt, 1-500pt)
DIV1 250pt
题意:用数组A表示置换,由该置换得到数组B(B[0] = 0, B[i] = A[B[i-1]])。给定A,求一个A',使得由A'得到的B为单循环置换且A'与A的差距最小。定义A与A'的差距为,有多少个i满足A[i] != A'[i]。返回最小差距值。A.size() <= 50。
解法:要得到的B为单循环置换,则A'也为单循环置换。如果置换A含有t个循环节,if (t==1)差距为0,否则最小差距为t,原因是可以通过交换某两个数的位置,使得两个循环变为1个循环。
tag:math, permutation
1 // BEGIN CUT HERE 2 /* 3 * Author: plum rain 4 * score : 5 */ 6 /* 7 8 */ 9 // END CUT HERE 10 #line 11 "PerfectPermutation.cpp" 11 #include <sstream> 12 #include <stdexcept> 13 #include <functional> 14 #include <iomanip> 15 #include <numeric> 16 #include <fstream> 17 #include <cctype> 18 #include <iostream> 19 #include <cstdio> 20 #include <vector> 21 #include <cstring> 22 #include <cmath> 23 #include <algorithm> 24 #include <cstdlib> 25 #include <set> 26 #include <queue> 27 #include <bitset> 28 #include <list> 29 #include <string> 30 #include <utility> 31 #include <map> 32 #include <ctime> 33 #include <stack> 34 35 using namespace std; 36 37 #define clr0(x) memset(x, 0, sizeof(x)) 38 #define clr1(x) memset(x, -1, sizeof(x)) 39 #define pb push_back 40 #define sz(v) ((int)(v).size()) 41 #define all(t) t.begin(),t.end() 42 #define zero(x) (((x)>0?(x):-(x))<eps) 43 #define out(x) cout<<#x<<":"<<(x)<<endl 44 #define tst(a) cout<<a<<" " 45 #define tst1(a) cout<<#a<<endl 46 #define CINBEQUICKER std::ios::sync_with_stdio(false) 47 48 typedef vector<int> vi; 49 typedef vector<string> vs; 50 typedef vector<double> vd; 51 typedef pair<int, int> pii; 52 typedef long long int64; 53 54 const double eps = 1e-8; 55 const double PI = atan(1.0)*4; 56 const int inf = 2139062143 / 2; 57 58 class PerfectPermutation 59 { 60 public: 61 bool v[100]; 62 int reorder(vector <int> p){ 63 clr0 (v); 64 int cnt = 0; 65 for (int i = 0; i < sz(p); ++ i) if (!v[p[i]]){ 66 int t = p[i]; 67 while (!v[t]) 68 v[t] = 1, t = p[t]; 69 ++ cnt; 70 } 71 if (cnt == 1) return 0; 72 return cnt; 73 } 74 75 // BEGIN CUT HERE 76 public: 77 void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); } 78 private: 79 template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } 80 void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } 81 void test_case_0() { int Arr0[] = {2, 0, 1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 0; verify_case(0, Arg1, reorder(Arg0)); } 82 void test_case_1() { int Arr0[] = {2, 0, 1, 4, 3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 2; verify_case(1, Arg1, reorder(Arg0)); } 83 void test_case_2() { int Arr0[] = {2, 3, 0, 1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 2; verify_case(2, Arg1, reorder(Arg0)); } 84 void test_case_3() { int Arr0[] = {0, 5, 3, 2, 1, 4}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 3; verify_case(3, Arg1, reorder(Arg0)); } 85 void test_case_4() { int Arr0[] = {4, 2, 6, 0, 3, 5, 9, 7, 8, 1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 5; verify_case(4, Arg1, reorder(Arg0)); } 86 87 // END CUT HERE 88 89 }; 90 91 // BEGIN CUT HERE 92 int main() 93 { 94 // freopen( "a.out" , "w" , stdout ); 95 PerfectPermutation ___test; 96 ___test.run_test(-1); 97 return 0; 98 } 99 // END CUT HERE
DIV1 500pt
题意:在一个无向图G中,可以做这样一种操作:
选取一组点(A,B,C,D),其中AB有边直接连接,CD有边直接连接,AC,AD,BC,BD无直连边。那么毁坏AB,CD相连的边,并重新连接AC和BD,或者重新连接AD和BC。
对于一张给定图,问最少多少次操作才能使其变为连通图,如果不能变为连通图输出-1。
解法:我YY了一个结论。。。如果G中已经连的边数<G中的点数-1,则输出-1;如果存在某个连通块点数为1,输出-1;否则输出连通块的数目-1。
下面是证明:称题目所给操作为L操作。
由题可以推出以下几点:1、L操作不改变边的数量;2、如果去除了AB相连的边,AB还是在同一个连通块中,即AB在某个环上,则L操作可以将两个连通块变为一个;3、如果某个连通块的边数>=点数,即该连通块含有环,那么一定能够通过L操作将它与另一个含有边的连通块融合为一个。而连通块含有边的条件就是点数大于1;4、对于连通块的数目,一次L操作要么不改变连通块的数目,要么使连通快的数目减1。
由1,2,3可知,当G中边数>=点数且不存在点数为1的连通块时,可通过不断进行L操作来将将连通块数目减少到1,即此时一定可以将G变为连通图。
由4可知,每次L操作只能使连通块数目减1,则一定需要连通块数目-1次L操作才能将G变为联通图。所以,问题得证。
Ps:官方题解貌似使用记录所有联通块的点数和边数,不断合并联通块的方式来做的。我的代码比它的简单多了^ ^。
tag:think, graph, good
1 // BEGIN CUT HERE 2 /* 3 * Author: plum rain 4 * score : 5 */ 6 /* 7 8 */ 9 // END CUT HERE 10 #line 11 "StrangeCountry.cpp" 11 #include <sstream> 12 #include <stdexcept> 13 #include <functional> 14 #include <iomanip> 15 #include <numeric> 16 #include <fstream> 17 #include <cctype> 18 #include <iostream> 19 #include <cstdio> 20 #include <vector> 21 #include <cstring> 22 #include <cmath> 23 #include <algorithm> 24 #include <cstdlib> 25 #include <set> 26 #include <queue> 27 #include <bitset> 28 #include <list> 29 #include <string> 30 #include <utility> 31 #include <map> 32 #include <ctime> 33 #include <stack> 34 35 using namespace std; 36 37 #define clr0(x) memset(x, 0, sizeof(x)) 38 #define clr1(x) memset(x, -1, sizeof(x)) 39 #define pb push_back 40 #define sz(v) ((int)(v).size()) 41 #define all(t) t.begin(),t.end() 42 #define zero(x) (((x)>0?(x):-(x))<eps) 43 #define out(x) cout<<#x<<":"<<(x)<<endl 44 #define tst(a) cout<<a<<" " 45 #define tst1(a) cout<<#a<<endl 46 #define CINBEQUICKER std::ios::sync_with_stdio(false) 47 48 typedef vector<int> vi; 49 typedef vector<string> vs; 50 typedef vector<double> vd; 51 typedef pair<int, int> pii; 52 typedef long long int64; 53 54 const double eps = 1e-8; 55 const double PI = atan(1.0)*4; 56 const int inf = 2139062143 / 2; 57 58 class StrangeCountry 59 { 60 public: 61 int f[100], cnt[100]; 62 int find (int x) 63 { 64 if (x != f[x]) f[x] = find(f[x]); 65 return f[x]; 66 } 67 int transform(vector <string> g){ 68 int num = 0; 69 for (int i = 0; i < sz(g); ++ i) 70 for (int j = 0; j < sz(g); ++ j) 71 if (i != j && g[i][j] == 'Y') ++ num; 72 num /= 2; 73 if (num < sz(g)-1) return -1; 74 75 for (int i = 0; i < sz(g); ++ i) f[i] = i; 76 for (int i = 0; i < sz(g); ++ i) 77 for (int j = 0; j < sz(g); ++ j) if (g[i][j] == 'Y'){ 78 int t1 = find(i), t2 = find(j); 79 if (t1 != t2) f[t1] = t2; 80 } 81 int ret = 0; 82 clr0 (cnt); 83 for (int i = 0; i < sz(g); ++ i){ 84 int t = find (i); 85 if (!cnt[t]) ++ ret; 86 ++ cnt[t]; 87 } 88 for (int i = 0; i < sz(g); ++ i) 89 if (cnt[i] == 1) return -1; 90 return ret - 1; 91 } 92 93 // BEGIN CUT HERE 94 public: 95 void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); } 96 private: 97 template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } 98 void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } 99 void test_case_0() { string Arr0[] = {"NYNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYYYNN", "YNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYYYNN", "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNN", "NNNNNNNNNNNNNYNNNNNNNNNNNNNNYNNNNNNNNNNNNNNN", "YNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYYYNN", "NNNNNNNNNYNNNNNNNNNNNNNNNYYNNNNNNNNNNNNNNNNN", "NNNNNNNNYNNNYNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNY", "NNNNNNNNNNNNNYNNNNNNNYNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNYNNNNNNNNNNNNNNNYYNNNNNYNNNNNNNNNNN", "NNNNNNYNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNYNNNYNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNYNNNNNNNNY", "NNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNYNNNNNN", "NNNNNNNNNNYNNNNYNNNNNNNNNNNNNNNNNNYNNNNNNNNY", "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNYN", "NNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNYNNNNNNNNNNNNNNNNNYNNNNNNYNYNNNNN", "NNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNNNNNNYNNYNNNNNNNNNNNNN", "NNNNNNNNNNNNNNYNYNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNYNNNYYNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNYNNNYNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNNYNNNNNNYNNNNNNNNNNNNN", "NNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNNYNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNNYNNNYNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNNYN", "NNNNNNNNNNNNYNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNYNNNNNNNN", "NNNNNNNNNNNNNNNYNYNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNYNNNNN", "NNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNN", "NNNNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNYNNNNNNN", "YYNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYYNN", "YYNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYNYNN", "YYNNNNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNYYNNN", "NNNNNNNNNNNNNNNNNNNYNNNNNNNNNNNYNNNNNNNNNNNN", "NNNNNNNNNNYNNNNYNYNNNNNNNNNNNNNNNNNNNNNNNNNN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 0; verify_case(0, Arg1, transform(Arg0)); } 100 void test_case_1() { string Arr0[] = {"NYYNN", 101 "YNYNN", 102 "YYNNN", 103 "NNNNY", 104 "NNNYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 1; verify_case(1, Arg1, transform(Arg0)); } 105 void test_case_2() { string Arr0[] = {"NYYNNNN", 106 "YNYNNNN", 107 "YYNNNNN", 108 "NNNNYYN", 109 "NNNYNYY", 110 "NNNYYNY", 111 "NNNNYYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 1; verify_case(2, Arg1, transform(Arg0)); } 112 void test_case_3() { string Arr0[] = {"NYNYNNNNNNNN", 113 "YNYNNNNNNNNN", 114 "NYNYYNNNNNNN", 115 "YNYNNNNNNNNN", 116 "NNYNNYYNNNNN", 117 "NNNNYNYNNNNN", 118 "NNNNYYNNNNNN", 119 "NNNNNNNNYYNN", 120 "NNNNNNNYNYNN", 121 "NNNNNNNYYNNN", 122 "NNNNNNNNNNNY", 123 "NNNNNNNNNNYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 2; verify_case(3, Arg1, transform(Arg0)); } 124 void test_case_4() { string Arr0[] = {"NYNNNN", 125 "YNYNNN", 126 "NYNYNN", 127 "NNYNNN", 128 "NNNNNY", 129 "NNNNYN"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = -1; verify_case(4, Arg1, transform(Arg0)); } 130 131 // END CUT HERE 132 133 }; 134 135 // BEGIN CUT HERE 136 int main() 137 { 138 // freopen( "a.out" , "w" , stdout ); 139 StrangeCountry ___test; 140 ___test.run_test(-1); 141 return 0; 142 } 143 // END CUT HERE
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。