题意:给出一颗树(也有可能是多棵树,那就每棵树分别计算后求和,需要自己先构造),书上的节点有颜色和tag两种信息。颜色共有7种,tag有3种,分别是“u”,“i” ,“b”类型的tag。我们要对这棵树进行染色,每次染色,可以对当前节点染色,也可以对其子树染色。对子树染色时,每次染色能且仅能将所有类型某一tag的节点染成某一相同颜色。问至少需要染色多少次,才能将每个节点染成其所需的相应颜色。
解题思路:我们要得到的答案为某一最优解,因此能够想到用dp做,树上的dp自然就是树形dp了。dp[id][i][j][k]表示将id节点染成其所需的颜色,将其子树中tag类型为u的节点染成 i 颜色,将其子树中tag类型为i的节点染成 j 颜色,将其子树中tag类型为b的节点染成k颜色,至少需要几次。
#include <cstdio> #include <cstring> #include <cctype> #include <cstdlib> #include <cmath> #include <ctime> #include <iostream> #include <map> #include <set> #include <list> #include <sstream> #include <queue> #include <string> #include <deque> #include <stack> #include <vector> #include <bitset> #include <algorithm> using namespace std; #define clr(a, x) memset(a, x, sizeof(a)) #define rep(i, n) for (int i = 0; i < (int)(n); i++) #define REP(i,a,b) for(int i=a;i<=b;i++) template <class T> void checkmax(T &t, T x) { if (x > t) t = x; } template <class T> void checkmin(T &t, T x) { if (x < t) t = x; } template <class T> void _checkmax(T &t, T x) { if (t == -1 || x > t) t = x; } template <class T> void _checkmin(T &t, T x) { if (t == -1 || x < t) t = x; } typedef long long ll; struct Edge { int t , next ; } edge[111111] ; int head[111] , tot ; class CssRules { public: int col[111] , tag[111] , du[111] ; int min ( int a , int b ) { return a < b ? a : b ; } void new_edge ( int a , int b ) { edge[tot].t = b ; edge[tot].next = head[a] ; head[a] = tot ++ ; } int dp[111][10][10][10] ; void init () { tot = 0 ; memset ( head , -1 , sizeof ( head ) ) ; int i , j , k , l ; memset ( du , 0 , sizeof ( du ) ) ; memset ( dp , -1 , sizeof ( dp ) ) ; } int dfs ( int id , int u , int I , int b ) { if ( head[id] == -1 ) { if ( tag[id] == 1 ) return u != col[id] ; if ( tag[id] == 2 ) return I != col[id] ; if ( tag[id] == 3 ) return b != col[id] ; } if ( dp[id][u][I][b] != -1 ) return dp[id][u][I][b] ; int i , j , k , l , ret = 0 , add = 111111111 ; if ( tag[id] == 1 ) ret = ( u != col[id] ) ; if ( tag[id] == 2 ) ret = ( I != col[id] ) ; if ( tag[id] == 3 ) ret = ( b != col[id] ) ; for ( i = 0 ; i < 8 ; i ++ ) for ( j = 0 ; j < 8 ; j ++ ) for ( k = 0 ; k < 8 ; k ++ ) { if ( ( u && !i ) || ( I && !j ) || ( b && !k ) ) continue ; int cnt = (u!=i) + (I!=j) + (b!=k) ; for ( l = head[id] ; l != -1 ; l = edge[l].next ) cnt += dfs ( edge[l].t , i , j , k ) ; add = min ( cnt , add ) ; } return dp[id][u][I][b] = ret + add ; } int getMinimalCssRuleCount(vector <string> xthml) { string s ; init () ; int k = xthml.size () , i , j , l , m ; s = "" ; int last[1000] , top = 0 ; for ( i = 0 ; i < k ; i ++ ) s += xthml[i] ; k = s.size () ; int id = 0 ; for ( i = 0 ; i < k ; i ++ ) { if ( s[i] == '<' && s[i+1] != '/' ) { id ++ ; if ( top != 0 ) new_edge ( last[top] , id ) , du[id] ++ ; last[++top] = id ; if ( s[i+1] == 'u' ) tag[id] = 1 ; if ( s[i+1] == 'i' ) tag[id] = 2 ; if ( s[i+1] == 'b' ) tag[id] = 3 ; } else if ( s[i] == '<' && s[i+1] == '/' ) top -- ; else if ( s[i] == ':' ) { if ( s[i+1] == 'r' ) col[id] = 1 ; else if ( s[i+1] == 'w' ) col[id] = 2 ; else if ( s[i+1] == 'y' ) col[id] = 3 ; else if ( s[i+1] == 'b' && s[i+3] == 'a' ) col[id] = 4 ; else if ( s[i+1] == 'b' && s[i+3] == 'u' ) col[id] = 5 ; else if ( s[i+1] == 'g' && s[i+3] == 'a' ) col[id] = 6 ; else col[id] = 7 ; } } int ans = 0 ; for ( i = 1 ; i <= id ; i ++ ) if ( du[i] == 0 ) { int mx = 111111111 ; for ( j = 0 ; j < 8 ; j ++ ) for ( k = 0 ; k < 8 ; k ++ ) for ( l = 0 ; l < 8 ; l ++ ) { int add = ( l != 0 ) + ( j != 0 ) + ( k != 0 ) + 1 ; for ( m = head[i] ; m != -1 ; m = edge[m].next ) add += dfs ( edge[m].t , j , k , l ) ; mx = min ( mx , add ) ; } ans += mx ; } return ans ; } // BEGIN CUT HERE public: 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(); } private: 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(); } 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; } } void test_case_0() { string Arr0[] = {"<b id='x' style='color:red'></b>"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 1; verify_case(0, Arg1, getMinimalCssRuleCount(Arg0)); } void test_case_1() { string Arr0[] = {"<b id='x' style='color:red'>","<b id='y' style='color:red'>", "<b id='z' style='color:red'>","</b></b></b>"} ; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 2; verify_case(1, Arg1, getMinimalCssRuleCount(Arg0)); } void test_case_2() { string Arr0[] = {"<b id='x' style='color:red'>", "<b id='y' style='color:red'>", "<b id='w' style='color:red'>", "</b>", "</b>", "<u id='z' style='color:red'>", "</u>", "</b>"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 3; verify_case(2, Arg1, getMinimalCssRuleCount(Arg0)); } void test_case_3() { string Arr0[] = {"<b id='x' style='color:red'>", "<i id='y' style='color:black'>", "<u id='w' style='color:white'>", "</u>", "</i>", "<u id='z' style='color:yellow'>", "</u>", "</b>"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 4; verify_case(3, Arg1, getMinimalCssRuleCount(Arg0)); } void test_case_4() { string Arr0[] = {"<b id='x' style='col", "or:red'></b>", "<b id=", "'xx' style='color", ":red'></b>"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 2; verify_case(4, Arg1, getMinimalCssRuleCount(Arg0)); } // END CUT HERE }; // BEGIN CUT HERE int main() { CssRules ___test; ___test.run_test(-1); } // END CUT HERE