zoukankan      html  css  js  c++  java
  • 【atcoder F

    F- Namori

    http://agc004.contest.atcoder.jp/tasks/agc004_f


    Time limit : 2sec / Memory limit : 256MB

    Score : 2200 points

    Problem Statement

    You are given an undirected graph with N vertices and M edges. Here, N−1≤MN holds and the graph is connected. There are no self-loops or multiple edges in this graph.

    The vertices are numbered 1 through N, and the edges are numbered 1 through M. Edge i connects vertices ai and bi.

    The color of each vertex can be either white or black. Initially, all the vertices are white. Snuke is trying to turn all the vertices black by performing the following operation some number of times:

    • Select a pair of adjacent vertices with the same color, and invert the colors of those vertices. That is, if the vertices are both white, then turn them black, and vice versa.

    Determine if it is possible to turn all the vertices black. If the answer is positive, find the minimum number of times the operation needs to be performed in order to achieve the objective.

    Constraints

    • 2≤N≤105
    • N−1≤MN
    • 1≤ai,biN
    • There are no self-loops or multiple edges in the given graph.
    • The given graph is connected.

    Partial Score

    • In the test set worth 1500 points, M=N−1.

    Input

    The input is given from Standard Input in the following format:

    NMa1b1a2b2:aMbM

    Output

    If it is possible to turn all the vertices black, print the minimum number of times the operation needs to be performed in order to achieve the objective. Otherwise, print -1 instead.


    Sample Input 1

    Copy
    6 5
    1 2
    1 3
    1 4
    2 5
    2 6
    

    Sample Output 1

    Copy
    5
    

    For example, it is possible to perform the operations as shown in the following diagram:


    Sample Input 2

    Copy
    3 2
    1 2
    2 3
    

    Sample Output 2

    Copy
    -1
    

    It is not possible to turn all the vertices black.


    Sample Input 3

    Copy
    4 4
    1 2
    2 3
    3 4
    4 1
    

    Sample Output 3

    Copy
    2
    

    This case is not included in the test set for the partial score.


    Sample Input 4

    Copy
    6 6
    1 2
    2 3
    3 1
    1 4
    1 5
    1 6
    

    Sample Output 4

    Copy
    7
    

    This case is not included in the test set for the partial score.

    【分析】

      这题真神!!

      如果是一棵树的话。

      树是二分图,所以我们将他黑白染色,问题变成了,可以交换相邻的黑色和白色,使得最后图黑白倒置。

      把白色看成空格,黑色看成棋子,就是树上有x个棋子,你可以往空格里面移动,问你最少多少步到达目标状态。

      在树上,其实方案是唯一的,你求一下子树里面现在有多少个棋子,目标是多少个棋子,你就知道一定会从父亲那里运过来多少棋子(或者从这个运向父亲多少个棋子)

      这个是直接求就可以了的,就是$sum ai-bi$

      黑点个数初末态不同则无解。

      当有环怎么办?

      我们分类讨论:

      1、构成奇环,多了的一条边连向的两点是同色的,就是说两个点那里可以同时加2个黑点或者同时减两个黑点,加/减多少个黑点你是知道的,(黑点奇偶初末态不同则无解),你就直接把那些黑点加上去,然后做法跟前面一样了。

      2、构成偶环,就是说多了的那条边也可以运棋子,假设这条边向上运了x个棋子,然后就也是树上的问题。你的ans最后会写成|Ai-x|或|Ai+x|或|Ai|的形式,这种形式的和很经典啦,就是数轴上的距离和,我们x取其中的中位数就能算出最优解。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 #define Maxn 100010
      8 #define LL long long
      9 const int INF=1000010;
     10 
     11 int mymin(int x,int y) {return x<y?x:y;}
     12 
     13 struct node
     14 {
     15     int x,y,next;
     16 }t[Maxn*2];
     17 int len,first[Maxn];
     18 
     19 void ins(int x,int y)
     20 {
     21     t[++len].x=x;t[len].y=y;
     22     t[len].next=first[x];first[x]=len;
     23 }
     24 
     25 int r1,r2,ad;
     26 int sm[Maxn],ss[Maxn],ans,d[Maxn],h[Maxn];
     27 int dfs(int x,int fa,int dep)
     28 {
     29     sm[x]=1;ss[x]=dep;d[x]=dep;
     30     if(x==r1||x==r2) sm[x]+=ad,ss[x]+=ad;
     31     int tt=0;
     32     for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa)
     33     {
     34         int y=t[i].y;
     35         tt+=dfs(y,x,1-dep);
     36         sm[x]+=sm[y];ss[x]+=ss[y];
     37     }
     38     if(x==r1) tt++;
     39     if(x==r2) tt--;
     40     if(tt==-1) h[++h[0]]=ss[x]-(sm[x]-ss[x]);
     41     else if(tt==1) h[++h[0]]=(sm[x]-ss[x])-ss[x];
     42     else ans+=abs(ss[x]-(sm[x]-ss[x]));
     43     // ans+=abs(ss[x]-(sm[x]-ss[x]));
     44     return tt;
     45 }
     46 
     47 int ff[Maxn];
     48 int ffa(int x)
     49 {
     50     if(ff[x]!=x) ff[x]=ffa(ff[x]);
     51     return ff[x];
     52 }
     53 
     54 int main()
     55 {
     56     // int T;
     57     // scanf("%d",&T);
     58     // while(T--)
     59     {
     60         int n,m;r1=r2=0;
     61         scanf("%d%d",&n,&m);
     62         len=0;
     63         memset(first,0,sizeof(first));
     64         for(int i=1;i<=n;i++) ff[i]=i;
     65         for(int i=1;i<=m;i++)
     66         {
     67             int x,y;
     68             scanf("%d%d",&x,&y);
     69             if(ffa(x)!=ffa(y))
     70             {
     71                 ff[ffa(x)]=ffa(y);
     72                 ins(x,y);ins(y,x);
     73             }
     74             else r1=x,r2=y;
     75         }
     76         if(m==n-1)
     77         {
     78             dfs(1,0,0);
     79             ans=0;
     80             for(int i=1;i<=n;i++) ans+=abs(ss[i]-(sm[i]-ss[i]));
     81             if(sm[1]-ss[1]!=ss[1]) printf("-1
    ");
     82             else printf("%d
    ",ans);
     83         }
     84         else
     85         {
     86             // printf("-2
    ");
     87             ad=0;
     88             dfs(1,0,0);
     89             if(d[r1]==d[r2])
     90             {
     91                 ad=abs(ss[1]-(sm[1]-ss[1]));
     92                 if(ad&1) printf("-1
    ");
     93                 else
     94                 {
     95                     ad/=2;
     96                     if(ss[1]>sm[1]-ss[1]) dfs(1,0,1);
     97                     else dfs(1,0,0);
     98                     ans=ad;
     99                     for(int i=1;i<=n;i++) ans+=abs(ss[i]-(sm[i]-ss[i]));
    100                     printf("%d
    ",ans);
    101                 }
    102             }
    103             else
    104             {
    105                 h[0]=0;h[++h[0]]=0;
    106                 ans=0;
    107                 dfs(1,0,0);
    108                 if(sm[1]-ss[1]!=ss[1]) printf("-1
    ");
    109                 else
    110                 {
    111                     sort(h+1,h+1+h[0]);
    112                     int x=h[h[0]/2+1];
    113                     for(int i=1;i<=h[0];i++) ans+=abs(h[i]-x);
    114                     printf("%d
    ",ans);
    115                 }
    116             }
    117         }
    118     }
    119     return 0;
    120 }
    View Code

    【代码有点丑。。

    2017-04-19 09:43:00

  • 相关阅读:
    对 Excel 工作簿中的数字签名和代码签名的说明
    单例模式
    面向对象
    Des对称加密
    Java获取电脑硬件信息
    鼠标双击事件不可描述的问题
    RSA不对称加密
    JTable表格案例
    控件刷新的奥秘
    反编译插件安装
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6731772.html
Copyright © 2011-2022 走看看