题意:给出一颗树(也有可能是多棵树,那就每棵树分别计算后求和,需要自己先构造),书上的节点有颜色和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