题目要求:
求出满足以下两个条件的子图数:
1.子图定点数大于等于2
2.子图中的所有边都大于(所有子图外的(与子图中的点有公共点的的边的长))
题解:
将边的长度离散化,从大到小枚举边长,每次统计最小边边长为枚举的边长的子图,累加即可.
/*
* File: main.cpp
* Author: swordholy
*
* Created on 2011年3月1日, 上午8:56
*/
#include <cstdlib>
#include <list>
#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <iterator>
#include <algorithm>
using namespace std;
int n,m;
#define MAXM 250005
#define MAXN 5005
struct edge
{
int s,t,l;
bool operator <(const edge &rhs) const
{
if (l<rhs.l) return true;
else return false;
}
};
edge e[MAXM];
list<int> LK[MAXN];
list<int>::iterator ita,itb;
int father[MAXN];
int ans;
int me[MAXN],ee[MAXN];
bool cnt[5005][5005];
int cha(int x)
{
if (x!=father[x])
father[x]=cha(father[x]);
return father[x];
}
void bing(int a,int b)
{
int i,j;
a=cha(a);
b=cha(b);
if (a==b) {ee[a]++;return ;}
father[b]=a;
ee[a]+=ee[b]+1;
me[a]+=me[b];
for(ita=LK[a].begin();ita!=LK[a].end();ita++)
for(itb=LK[b].begin();itb!=LK[b].end();itb++)
{
me[a]+=cnt[(*ita)][(*itb)];
}
LK[a].merge(LK[b]);
}
int calced[MAXN];
void calc_ans(int i)
{
int a;
a=cha(e[i].s);
if (calced[a]==e[i].l) return ;
if ( (ee[a]==me[a])&&(calced[a]!=e[i].l) )
{
ans+=LK[a].size();
calced[a]=e[i].l;
}
}
int main(int argc, char** argv) {
int i,j,t,u,x,y,z;
cin>>t;
for(u=1;u<=t;u++)
{
cin>>n>>m;
memset(cnt,0,sizeof(cnt));
for(i=1;i<=m;i++)
{
cin>>e[i].s>>e[i].t>>e[i].l;
cnt[e[i].s][e[i].t]=cnt[e[i].t][e[i].s]=1;
}
sort(e+1,e+m+1);
e[0].l=-1;
ans=0;
memset(me,0,sizeof(me));
memset(ee,0,sizeof(ee));
memset(calced,-1,sizeof(calced));
for(i=1;i<=n;i++)
{
father[i]=i;
LK[i].clear();
LK[i].push_back(i);
}
int lasti=m+1,ii;
for(i=m;i>=1;i--)
{
if (e[i].l==e[i-1].l)
{
bing(e[i].s,e[i].t);
}
else
{
bing(e[i].s,e[i].t);
for(ii=i;ii<lasti;ii++)
calc_ans(ii);
lasti=i;
}
}
cout<<ans<<endl;
}
return 0;
}