BZOJ 3197 assassin(树形DP+费用流)

标签: dp 匹配 树哈希
17人阅读 评论(2) 收藏 举报
分类:

题目链接:BZOJ 3197

题目大意:给出两棵节点被染成黑白两色的无根树,问第一棵树经过重标号后至少要反转多少个节点的颜色使之与第二棵树完全相同。

题解:类似BZOJ3162独钓寒江雪 的解法,可以将树的重心作为根DP,设f[i][j]表示若使第一棵树中以i为根的子树和第二棵树中以j为根的子树完全相同需要反转至少多少个节点的颜色。转移的时候对于同构的子树用费用流转移(还是比较好理解的,详见代码)。

code(第一次写费用流转移的DP,有参考大牛们的BLOG)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 705
#define seed 9875321
#define inf 1000000000
using namespace std;
inline int read()
{
    char c=getchar(); int num=0,f=1;
    while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
    while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }
    return num*f;
}
struct edge{
    int to,ne;
    bool del;
}e[N<<1];
int n,tot=1,head[N],root,fa[N],siz[N],f[N][N],tmp[N],a[N],b[N],deep[N],mn=inf,h[2];
inline void push(int x,int y) { e[++tot].to=y; e[tot].ne=head[x]; head[x]=tot; }
unsigned long long H[N];
pair<int,pair<unsigned long long,int> > w[N];
pair<unsigned long long,int> p1[N],p2[N];
struct Network{
    int S,T,tot,head[25],dis[25],pre[25]; bool vis[25];
    struct edge{
        int fr,to,ne,c,v;
    }e[450];
    void clear(int n) { S=0,T=n+1; tot=1; for (int i=S;i<=T;i++) head[i]=0; }
    void push(int x,int y,int flow,int cost)
    {
        e[++tot].fr=x; e[tot].to=y; e[tot].v=flow; e[tot].c=cost; e[tot].ne=head[x]; head[x]=tot;
        e[++tot].fr=y; e[tot].to=x; e[tot].v=0; e[tot].c=-cost; e[tot].ne=head[y]; head[y]=tot;
    }
    bool spfa()
    {
        for (int i=S;i<=T;i++) dis[i]=inf;
        queue<int> q; dis[S]=0; vis[S]=true; q.push(S);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (int i=head[now];i;i=e[i].ne)
            {
                int v=e[i].to;
                if (e[i].v&&dis[now]+e[i].c<dis[v])
                {
                    dis[v]=dis[now]+e[i].c;
                    pre[v]=i;
                    if (!vis[v]) vis[v]=true,q.push(v);
                }
            }
            vis[now]=false;
        }
        return dis[T]!=inf;
    }
    int mcf()
    {
        for (int i=T;i!=S;i=e[pre[i]].fr) e[pre[i]].v--,e[pre[i]^1].v++;
        return dis[T];
    }
}flow;
void getrt(int now,int pre)
{
    siz[now]=1; int tmp=0;
    for (int i=head[now];i;i=e[i].ne)
    {
        int v=e[i].to; if (v==pre) continue;
        getrt(v,now); siz[now]+=siz[v];
        tmp=max(tmp,siz[v]);
    }
    tmp=max(tmp,n-siz[now]);
    if (tmp<mn) mn=tmp,h[0]=now,h[1]=0;
     else if (tmp==mn) h[1]=now;
}
void geth(int now,int pre,int dep)
{
    fa[now]=pre; deep[now]=dep;
    for (int i=head[now];i;i=e[i].ne)
    {
        int v=e[i].to; if (v==pre||e[i].del) continue;
        geth(v,now,dep+1);
    }
    int top=0;
    for (int i=head[now];i;i=e[i].ne)
    {
        int v=e[i].to; if (v==pre||e[i].del) continue;
        tmp[++top]=H[v];
    }
    sort(tmp+1,tmp+top+1);
    H[now]=233;
    for (int i=1;i<=top;i++) (((H[now]*=seed)^=tmp[i])+=tmp[i])^=tmp[i];
}
void solve(int x,int y)
{
    int s1=0,s2=0;
    for (int i=head[x];i;i=e[i].ne)
    {
        int v=e[i].to; if (v==fa[x]||e[i].del) continue;
        p1[++s1]=make_pair(H[v],v);
    }
    for (int i=head[y];i;i=e[i].ne)
    {
        int v=e[i].to; if (v==fa[y]||e[i].del) continue;
        p2[++s2]=make_pair(H[v],v);
    }
    sort(p1+1,p1+s1+1); sort(p2+1,p2+s2+1);
    for (int i=1;i<=s1;i++)
    {
        int j=i;
        while (j<s1&&p1[j+1].first==p1[j].first) j++;
        int len=j-i+1;
        flow.clear(len*2);
        for (int k=i;k<=j;k++)
         for (int l=i;l<=j;l++)
          flow.push(k-i+1,l-i+1+len,1,f[p1[k].second][p2[l].second]);
        for (int k=1;k<=len;k++)
         flow.push(flow.S,k,1,0),flow.push(k+len,flow.T,1,0);
        while (flow.spfa()) f[x][y]+=flow.mcf();
        i=j;
    }
    if (a[x]!=b[y]) f[x][y]++;
}
int main()
{
    n=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        push(x,y); push(y,x);
    }
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=n;i++) b[i]=read();
    getrt(1,0);
    if (h[1])
    {
        for (int i=head[h[0]];i;i=e[i].ne)
         if (e[i].to==h[1]) e[i].to=e[i^1].to=root=n+1;
        push(n+1,h[0]); push(n+1,h[1]); n++;
    }
    else root=h[0];
    geth(root,0,1);
    for (int i=1;i<=n;i++) w[i]=make_pair(-deep[i],make_pair(H[i],i));
    sort(w+1,w+n+1);
    for (int i=1;i<=n;i++)
    {
        int j=i;
        while (j<n&&w[j+1].first==w[j].first&&w[j+1].second.first==w[j].second.first) j++;
        for (int k=i;k<=j;k++)
         for (int l=i;l<=j;l++)
          solve(w[k].second.second,w[l].second.second);
        i=j;
    }
    printf("%d",f[root][root]);
    return 0;
}
查看评论

第一本介绍Eclipse的书——Eclipse in Action

世上第一本详细介绍Eclipse的书。如果问我的意见,我会说这本书比《JBuilder实用技术手册》更有意义,因为我喜欢Eclipse胜于JBuilder。Manning Publications h...
  • gigix
  • gigix
  • 2003-06-10 11:11:00
  • 2053

[bzoj3197][SDOI2013]assassin

3197: [Sdoi2013]assassinTime Limit: 10 Sec Memory Limit: 256 MB Submit: 221 Solved: 113 [Submit]...
  • FZHvampire
  • FZHvampire
  • 2016-03-30 15:21:26
  • 578

[KM 树同构Hash DP] BZOJ 3197 [Sdoi2013]assassin

丢下题解跑:http://blog.csdn.net/PoPoQQQ/article/details/43206463 #include #include #include #include...
  • u014609452
  • u014609452
  • 2016-07-04 19:03:23
  • 315

BZOJ 3197 Sdoi2013 assassin 动态规划+树同构+费用流

题目大意:给定一棵树和两组权值,求第一组权值最少改变多少个之后这棵树经过重标号之后与第二组权值相同 这个题做法很神- - 首先和3162一样的处理方式 我们先找到这棵树的重心作为根 如果重心有两个就新...
  • PoPoQQQ
  • PoPoQQQ
  • 2015-01-27 23:35:56
  • 2004

【JZOJ3296】【SDOI2013】刺客信条(assassin)

╰( ̄▽ ̄)╭Description故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客。最终,凭借着他的努力和出众的天赋,成...
  • hiweibolu
  • hiweibolu
  • 2017-03-07 15:42:16
  • 199

bzoj 3197: [Sdoi2013]assassin 树哈希+树形dp+费用流

题意给定一棵树和两组权值,求第一组权值最少改变多少个之后这棵树经过重标号之后与第二组权值相同。 n...
  • qq_33229466
  • qq_33229466
  • 2017-10-07 16:56:46
  • 109

bzoj2159

【题意】 给出一棵nn个点的树,求对于每个点ii的d(i)d(i)值。d(i)=∑i≠x1≤x≤ndist(x,i)kd(i) = \sum_{1\leq x \leq n}^{i \not= x}...
  • BOYxiejunBOY
  • BOYxiejunBOY
  • 2017-02-26 08:16:38
  • 286

[BZOJ2159]Crash 的文明世界-Stirling数-动态规划

Crash 的文明世界DescriptionCrash 小朋友最近迷上了一款游戏——文明5(Civilization V)。在这个游戏中,玩家可以建立和发展自己的国家,通过外交和别的国家交流,或是通过...
  • zlttttt
  • zlttttt
  • 2017-12-30 23:56:41
  • 191

[BZOJ1283]序列(费用流)

题目描述传送门题解问题可以转化为选k次,每次选一个子序列,每一次选连续m个里面只能选一个 对序列中每一个元素建立一个点pip_i s->p1p_1,k,0,pnp_n->t,k,0 pip_i-...
  • Clove_unique
  • Clove_unique
  • 2017-01-30 21:41:30
  • 493

[最大费用可行流 || 单纯形] BZOJ 3118 Orz the MST

首先很容易根据树边非树边的大小关系列出线性关系 然后对偶一下 可以用线性规划 也可以跑费用流 把对偶后的线性约束写出来 建图就不难看懂了 #include #include #inc...
  • u014609452
  • u014609452
  • 2016-09-20 18:27:06
  • 839
    个人资料
    持之以恒
    等级:
    访问量: 2694
    积分: 380
    排名: 21万+
    最新评论
    友情链接