[JCWC2005]Draw

Einstein学起了画画,
此人比较懒~~,他希望用最少的笔画画出一张画。。。
给定一个无向图,包含 n 个顶点(编号1~n),m 条边,求最少用多少笔可以画出图
中所有的边

Input (draw.in)

第一行2个数n,m
以下m行每行 2个数a,b(a<>b) 表示a,b两点之间有一条边相连
一条边不会被描述多次

Output (draw.out)

一个数即问题的答案

Sample

Input 
5 5
2 3
2 4
2 5
3 4
4 5

output

1

约定

50%的数据n<=50,m<=100
100%的数据n<=1000,m<=100000

思路

  求一个无向图中有几个哈密尔顿路。也是求边的一笔画问题。

  概念补充

  奇点就是从这个点出发的线有奇数条,偶点就是从这个点出发的线有偶数条.

  关键部分

  如何判断一个图形是否可以一笔不重地画出

  ■⒈凡是由偶点组成的连通图,一定可以一笔画成。画时可以把任一偶点为起点,最后一定能以这个点为终点画完此图。

  ■⒉凡是只有两个奇点的连通图(其余都为偶点),一定可以一笔画成。画时必须把一个奇点为起点,另一个奇点终点。

  ■⒊其他情况的图都不能一笔画出。(奇点数除以二便可算出此图需几笔画成。)

  易错点

   注意此题可能图不是联通的,由样例就可以看出它是一个单独的点加上一个连通图。

     再比如这个例子,单纯的按照一般的算法写出来答案是1,显然答案是2,所以要统计输入数据中联通图的数量,再分别进行求解。并查集可以实现。

  

var n,m,i,u,v,sum1,sum2,mid:longint;
    b,f:array[0..1010] of longint;

procedure intt;
begin
    assign(input,'draw.in');
    assign(output,'draw.out');
    reset(input);
    rewrite(output);
end;

procedure outt;
begin
    close(input);
    close(output);
end;

procedure sort(l,r: longint);
      var
         i,j,x,y: longint;
      begin
         i:=l;
         j:=r;
         x:=f[(l+r) div 2];
         repeat
           while f[i]<x do
            inc(i);
           while x<f[j] do
            dec(j);
           if not(i>j) then
             begin
                y:=f[i];
                f[i]:=f[j];
                f[j]:=y;
                y:=b[i];
                b[i]:=b[j];
                b[j]:=y;
                inc(i);
                j:=j-1;
             end;
         until i>j;
         if l<j then
           sort(l,j);
         if i<r then
           sort(i,r);
      end;

function root(x:longint):Longint;
begin
    if f[x]=x then exit(x) else root:=root(f[x]);
    f[x]:=root;
    exit(root);
end;

begin
    intt;
    readln(n,m);
    for i:=1 to n do f[i]:=i;
    for i:=1 to m do
        begin
            read(u,v);
            if root(u)<>root(v) then
                f[root(u)]:=root(v);
            inc(b[u]);
            inc(b[v]);
        end;
    for i:=1 to n do mid:=root(i);
    sort(1,n);
    v:=n;
    while v>1 do
        begin
            while f[v-1]<>f[v] do dec(v);
            inc(sum2);
            mid:=f[v];
            while f[v]=mid do
                begin
                    if b[v] mod 2=1 then inc(sum1);
                    dec(v);
                end;
            if sum1>0 then sum1:=sum1-2;
            sum2:=sum2+sum1 div 2;
            sum1:=0;
        end;
    writeln((sum1 div 2)+sum2);
    outt;
end.
View Code

 

 

posted on 2015-10-24 19:20  川汉唐  阅读(379)  评论(0编辑  收藏  举报

导航