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);
}
}
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( "" );
}
}
#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