HDU 3212 Card Collection【两个虚拟根或者一个】 && HDU 2121 Ice_cream’s world II 【不定根的最小树形图】

HDU 3212 Card Collection【两个虚拟根或者一个】 && HDU 2121 Ice_cream’s world II 【不定根的最小树形图】

3212
地上有一堆卡片。捡起来需要时间,必须一张一张捡起。根据给定关系,如果有特定卡片b,捡起卡片a的时间会加快。
手里已有“THE_WINDY"卡。
连虚根1到所有卡片(除上述),权值为捡起该卡片的原本时间,其他边根据给定关系连接。再连虚根2到虚根1和”THE_WINDY",边权为已知总权和+1。做最小树形图,将得到的答案减小到sum+1以下(去掉多余的边,至多两条)。
ps当然一个虚根也可以做。
我擦,最后一题最小树形图竟然把模板打错了,wa了半天。
附代码:
/*
Coded by BUPT-[aswmtjdsj] @ Penalty
*/
#include 
< iostream >
#include 
< cstdio >
#include 
< cstring >
#include 
< cctype >
#include 
< string >
#include 
< sstream >
#include 
< fstream >
#include 
< algorithm >
#include 
< vector >
#include 
< bitset >
#include 
< ctime >
#include 
< cstdlib >
#include 
< map >
#include 
< set >
#include 
< cmath >
#include 
< queue >
#define  see(x) cerr << " LINE " << __LINE__ << ":" << #x << " : " << x << endl
#define  SP system("pause")
using   namespace  std;
const   double  pi  =  acos( - 1.0 );
const   double  eps  =  1e - 8 ;
const   int  inf  =   ~ 0u   >>   1 ;
const   int  dx[ 4 =  { 0 , 0 , - 1 , 1 };
const   int  dy[ 4 =  { - 1 , 1 , 0 , 0 };
#define  left(x) ((x) << 1)
#define  right(x) (((x) << 1) + 1)
#define  parent(x) ((x) >> 1)
#define  maxv 1000
#define  maxe (maxv * maxv)
#define  sqr(x) ((x) * (x))
#define  PQ priority_queue
#define  PB push_back
int  n;
#define  maxn 105
#define  maxm 400
int  cnt,cnt0;
#define  type int
struct  edge
{
    
int  p,q;
    type cost;
    edge(){}
    edge(
int  a, int  b,type c):p(a),q(b),cost(c){}
}e[maxm];
type 
in [maxn];
int  pre[maxn],vis[maxn],id[maxn];
type dirmst(
int  root, int  nv, int  ne)
{
    type ans 
=   0 ;
    
while ( 1 )
    {
        fill(
in , in   +  nv,inf);
        
for ( int  i  =   0 ;i  <  ne;i ++ )
        {
            
int  u  =  e[i].p;
            
int  v  =  e[i].q;
            
if (e[i].cost  <   in [v]  &&  u  !=  v)
            {
                pre[v] 
=  u;
                
in [v]  =  e[i].cost;
            }
        }
        
for ( int  i  =   0 ;i  <  nv;i ++ )
        {
            
if (i  ==  root)
                
continue ;
            
if ( in [i]  ==  inf)
                
return   - 1 ;
        }
        
int  cntnode  =   0 ;
        fill(id,id 
+  nv, - 1 );
        fill(vis,vis 
+  nv, - 1 );
        
in [root]  =   0 ;
        
for ( int  i  =   0 ;i  <  nv;i ++ )
        {
            ans 
+=   in [i];
            
int  v  =  i;
            
while (vis[v]  !=  i  &&  id[v]  ==   - 1   &&  v  !=  root)
            {
                vis[v] 
=  i;
                v 
=  pre[v];
            }
            
if (v  !=  root  &&  id[v]  ==   - 1 )
            {
                
for ( int  u  =  pre[v];u  !=  v;u  =  pre[u])
                    id[u] 
=  cntnode;
                id[v] 
=  cntnode ++ ;
            }
        }
        
if (cntnode  ==   0 )
            
break ;
        
for ( int  i  =   0 ;i  <  nv;i ++ )
            
if (id[i]  ==   - 1 )
                id[i] 
=  cntnode ++ ;
        
for ( int  i  =   0 ;i  <  ne;i ++ )
        {
            
int  v  =  e[i].p;
            e[i].p 
=  id[e[i].p];
            e[i].q 
=  id[e[i].q];
            
if (e[i].p  !=  e[i].q)
                e[i].cost 
-=   in [v];
        }
        nv 
=  cntnode;
        root 
=  id[root];
    }
    
return  ans;
}
int  main()
{
    
while (scanf( " %d " , & n)  ==   1   &&  n)
    {
        
int  sum  =   0 ;
        map
< string , int >  M;
        M[
" THE_WINDY " =   1 ;
        cnt 
=   2 ;
        cnt0 
=   0 ;
        
for ( int  i  =   1 ;i  <=  n;i ++ )
        {
            
char  opt[ 25 ];
            
int  num;
            scanf(
" %s %d " ,opt, & num);
            
string  a(opt);
            
if (M[a]  ==   0 )
                M[a]
= cnt ++ ;
            e[cnt0
++ =  edge( 0 ,M[a],num);
            sum 
+=  num;
            scanf(
" %s %d " ,opt, & num);
            
string  b(opt);
            
if (a  !=  b)
            {
                
if (M[b]  ==   0 )
                    M[b]
= cnt ++ ;
                e[cnt0
++ =  edge(M[b],M[a],num);
                sum 
+=  num;
            }
        }
        
for ( int  i  =   0 ;i  <=   1 ;i ++ )
            e[cnt0
++ =  edge(cnt,i,sum  +   1 );
        cnt
++ ;
        
int  ans  =  dirmst(cnt  -   1 ,cnt,cnt0);
        
while (ans  >  sum  +   1 )
            ans 
-=  sum  +   1 ;
        printf(
" %d\n " ,ans);
    }
}


2121
同一种思想,两种实现。- -||一种wa的莫名其妙,一种瞬间ac。怨念。

1000个点,10000条边,根未给定,找最小树形图,并输出根。
做法(根据notonlysuccess大神):加一个虚根,连到已有图中的所有点,边权为原图所有边权之和+1。
做完最小树形图之后的解减去这个值就是最小树形图的解的权和(如果大于这个值的两倍说明无解)。
输出根的时候挺蛋疼。把最初的图记下来,每次找最小入边的时候看看出点是不是虚根,维护一个值记录与虚根连接的点,最后一次被更新的点一定是实根。

附代码:
#include  < iostream >
#include 
< cstdio >
#include 
< cmath >
#include 
< cstring >
using   namespace  std;
#define  maxn 1005
#define  maxm 11005
#define  type int
const   int  inf  =   ~ 0u   >>   1 ;
struct  edge
{
    
int  u,v;
    type cost;
    
int  oldu,oldv;
    edge(){}
    edge(
int  a, int  b,type c, int  d, int  e):u(a),v(b),cost(c),oldu(d),oldv(e){}
}e[maxm];
int  pre[maxn],id[maxn],vis[maxn];
int  mark;
type 
in [maxn];
type dirmst(
int  root, int  nv, int  ne)
{
    type ret 
=   0 ;
    
int  cnt  =   0 ;
    
int  oldroot  =  root;
    
while ( 1 )
    {
        cnt
++ ;
        fill(
in , in   +  nv,inf);
        
for ( int  i  =   0 ;i  <  ne;i ++ )
        {
            
int  u  =  e[i].u;
            
int  v  =  e[i].v;
            
if (e[i].cost  <   in [v]  &&  u  !=  v)
            {
                
if (e[i].oldu  ==  oldroot)
                    mark 
=  e[i].oldv;
                pre[v] 
=  u;
                
in [v]  =  e[i].cost;
            }
        }
        
for ( int  i  =   0 ;i  < nv;i ++ )
        {
            
if (i  ==  root)
                
continue ;
            
if ( in [i]  ==  inf)
                
return   - 1 ;
        }
        
int  cntnode  =   0 ;
        fill(id,id 
+  nv, - 1 );
        fill(vis,vis 
+  nv, - 1 );
        
in [root]  =   0 ;
        
for ( int  i  =   0 ;i  <  nv;i ++ )
        {
            ret 
+=   in [i];
            
int  v  =  i;
            
while (vis[v]  !=  i  &&  id[v]  ==   - 1   &&  v  !=  root)
            {
                vis[v] 
=  i;
                v 
=  pre[v];
            }
            
if (v  !=  root  &&  id[v]  ==   - 1 )
            {
                
for ( int  u  =  pre[v];u  !=  v;u  =  pre[u])
                    id[u] 
=  cntnode;
                id[v] 
=  cntnode ++ ;
            }
        }
        
if (cntnode  ==   0 )
            
break ;
        
for ( int  i  =   0 ;i  <  nv;i ++ )
            
if (id[i]  ==   - 1 )
                id[i] 
=  cntnode ++ ;
        
for ( int  i  =   0 ;i  <  ne;i ++ )
        {
            
int  v  =  e[i].v;
            e[i].u 
=  id[e[i].u];
            e[i].v 
=  id[e[i].v];
            
if (e[i].u  !=  e[i].v)
                e[i].cost 
-=   in [v];
        }
        nv 
=  cntnode;
        root 
=  id[root];
    }
    
return  ret;
}
int  n,m;
int  main()
{
    
while (scanf( " %d %d " , & n, & m)  ==   2 )
    {
        
int  sum  =   0 ;
        mark 
=   - 1 ;
        
for ( int  i  =   0 ;i  <  m;i ++ )
        {
            
int  a,b,c;
            scanf(
" %d %d %d " , & a, & b, & c);
            e[i] 
=  edge(a,b,c,a,b);
            sum 
+=  c;
        }
        
int  temp  =  m;
        
for ( int  i  =   0 ;i  <  n;i ++ )
            e[temp
++ =  edge(n,i,sum  +   1 ,n,i);
        
int  ans  =  dirmst(n,n  +   1 ,temp);
        
if (ans  >   2   *  (sum  +   1 ))
            puts(
" impossible " );
        
else
            printf(
" %d %d\n " ,ans  -  sum  -   1 ,mark);
        puts(
"" );
    }
}

Down

你可能感兴趣的:(HDU 3212 Card Collection【两个虚拟根或者一个】 && HDU 2121 Ice_cream’s world II 【不定根的最小树形图】)