同时dp两个变量 即 —— 在 v1 最小的情况下 v2 最小
可以令dp的内容为 v1*M+v2 使得这个数值最小,M是一个比 v2最大值还要大的值。
这个题中,v1 为街灯的数量,v2 为被两个街灯照亮的数量 ,要求是 v1 最小 v2 最大 。 令 v2为 一个街灯照亮的路的数量,这样方向就一致了。
一共有两种决策,放灯还是不放灯,但是这个决策又和父节点有关。所以有必要在状态中描述父节点的状态。这样装填描述才完整。
dp[i][j] 表示以i为根节点(包括其与父亲那条边)所有边照亮要多少灯,j 为1 是在其父节点有灯的情况下,0是在无灯的情况下。
#include <stdio.h>
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
#include <stack>
using namespace std;
#define READ freopen("acm.in","r",stdin)
#define WRITE freopen("acm.out","w",stdout)
#define ll long long
#define PII pair<int,int>
#define PDI pair<double,int>
#define PDD pair<double,double>
#define MII map<int,int>::iterator
#define fst first
#define sec second
#define MS(x,d) memset(x,d,sizeof(x))
#define INF 0x3f3f3f3f
#define ALL(x) x.begin(),x.end()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MAX 500000
#define ROOT 0,n-1,1
#define PB push_back
#define FOR(a,b,c) for(int a=b;a<c;a++)
#define MOD 706679
#define keyTree (ch[ ch[root][1] ][0])
vector<int> G[2000];
int used[2000];
int dp[2000][2];
const int M=2000;
void dfs(int v,int fa)
{
used[v]=1;
if(G[v].size()==1&&used[G[v][0]])
{
//if(fa!=-1)
{
dp[v][0]=M+1;
dp[v][1]=1;
}
return ;
}
for(int i=0;i<G[v].size();i++)
{
int u=G[v][i];
if(u!=fa)
dfs(u,v);
}
{// don't put light
int d=0;
for(int i=0;i<G[v].size();i++)
{
int u=G[v][i];
if(u!=fa)
d+=dp[u][0];
}
if(fa!=-1)
d+=1;
//if(v==1)
// cout<<" v1 "<<d<<endl;
dp[v][1]=min(dp[v][1],d);
}
{// put light
int d=0;
d+=M;
for(int i=0;i<G[v].size();i++)
{
int u=G[v][i];
if(u!=fa)
{
d+=dp[u][1];
}
}
dp[v][0]=min(dp[v][0],d+1);
dp[v][1]=min(dp[v][1],d);
}
return ;
}
void dfs2(int u,int fa)
{
used[u]=1;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!used[v]&&v!=fa)
dfs2(v,u);
}
}
int main()
{
READ;
int cas;
scanf("%d",&cas);
while(cas--)
{
MS(used,0);
for(int i=0;i<2000;i++)
{
dp[i][0]=INF;
dp[i][1]=INF;
}
for(int i=0;i<2000;i++)
G[i].clear();
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int f,t;
scanf("%d%d",&f,&t);
G[f].PB(t);
G[t].PB(f);
}
int ans=0;
for(int i=0;i<n;i++)
{
if(!used[i])
{
dfs(i,-1);
ans+=min(dp[i][0],dp[i][1]);
}
}
cout<<ans/M<<" "<<m-ans%M<<" "<<ans%M<<endl;
}
return 0;
}