T1:
把所有边从大到小排序,for一遍,
对于每个点i开一个bitset,如果扫描到一条边(i,j) 那么bitset[j][i] = bitset[i][j] = 1
如果bitset[i] & bitset[j] > 0 那么说明i,j已经通过一个点k相连,即当前这条边就是答案
题目貌似并不考虑三点共线,也就是说貌似三点共线也算三角形(不用特判的程序都能过)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;
const int maxn = 3010;
typedef double DB;
struct E{
int a,b; DB len;
bool operator < (const E &B) const {
return len > B.len;
}
E(int _a = 0,int _b = 0,DB _len = 0) {a = _a,b = _b,len = _len;}
}edgs[maxn*maxn];
int n;
DB x[maxn],y[maxn];
bitset <maxn> bi[maxn],now;
DB cal(int i,int j)
{
DB X = x[i] - x[j];
DB Y = y[i] - y[j];
return sqrt(X*X + Y*Y);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("geometry.in","r",stdin);
freopen("geometry.out","w",stdout);
#endif
cin >> n;
for (int i = 1; i <= n; i++) {
int a,b; scanf("%d%d",&a,&b);
x[i] = a; y[i] = b;
}
int tot = 0;
for (int i = 1; i < n; i++)
for (int j = i+1; j <= n; j++)
edgs[tot++] = E(i,j,cal(i,j));
sort(edgs,edgs+tot); DB T = 2.00;
for (int i = 0; i < tot; i++) {
now = bi[edgs[i].a] & bi[edgs[i].b];
if (now.count() > 0) {
printf("%.3f",edgs[i].len/T);
return 0;
}
bi[edgs[i].a][edgs[i].b] = 1;
bi[edgs[i].b][edgs[i].a] = 1;
}
return 0;
}
T2:
强行树上dp,
先以1为根,
f[i]: i的子树中经过轻边的最小值
pass[i]:从i向它父亲的边被经过的次数
f[i] = ∑f[son] + ∑pass[son] - Max(pass[son])
pass[i] 通过树上前缀和求出
然后考虑换根
g[i]:以i为根的树经过轻边的最小值
g[i] = ∑f[son] + u + ∑pass[son] + pass[x] - Max(pass[son],pass[x])
u是指将i的父亲看做i的儿子后,该子树经过轻边的最小值
u = ∑f[son] + u的u - f[i] - Maxpass
那个Max的枚举以后要用寻找最大值和次大值,不要再用lm和rm....GG
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 1E5 + 10;
typedef long long LL;
LL f[maxn],g[maxn],pass[maxn],lm[maxn],rm[maxn];
int n,m,L[maxn],fa[maxn][20],son[maxn];
vector <int> v[maxn];
queue <int> Q;
void dfs1(int x,int from)
{
for (int i = 1; i < 20; i++)
fa[x][i] = fa[fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if (to == from) continue;
L[to] = L[x] + 1;
fa[to][0] = x; ++son[x];
dfs1(to,x);
}
}
void dfs2(int x,int from)
{
LL Max = 0,sum = 0;
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if (to == from) continue;
dfs2(to,x);
Max = max(Max,pass[to]);
sum += pass[to];
f[x] += f[to];
}
f[x] += (sum - Max);
}
void dfs3(int x,int from,LL u)
{
LL sum,ma1,ma2,pos,tot = 0;
sum = ma1 = ma2 = pass[x]; pos = x;
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if (to == from) continue;
tot += f[to];
sum += pass[to];
if (pass[to] >= ma1) {
ma2 = ma1; ma1 = pass[to]; pos = i;
}
else if (pass[to] > ma2) ma2 = pass[to];
}
g[x] = (tot + u + sum - ma1);
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if (to == from) continue;
LL next = u + tot - f[to] + sum - pass[to];
if (i == pos) next -= ma2;
else next -= ma1;
dfs3(to,x,next);
}
}
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
int Log; for (Log = 0; L[p] - (1<<Log) >= 1; Log++); --Log;
for (int j = Log; j >= 0; j--)
if (L[p] - (1<<j) >= L[q])
p = fa[p][j];
if (p == q) return p;
for (int j = Log; j >= 0; j--)
if (fa[p][j] != fa[q][j])
p = fa[p][j],q = fa[q][j];
return fa[p][0];
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
#endif
cin >> n >> m;
for (int i = 1; i < n; i++) {
int x,y; scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
L[1] = 1; dfs1(1,0);
for (int i = 1; i <= m; i++) {
int x,y; scanf("%d%d",&x,&y);
int Lca = LCA(x,y);
++pass[x]; ++pass[y]; pass[Lca] -= 2;
}
for (int i = 1; i <= n; i++)
if (!son[i]) Q.push(i);
while (!Q.empty()) {
int k = Q.front(); Q.pop();
int to = fa[k][0];
pass[to] += pass[k];
--son[to];
if (son[to] == 0) Q.push(to);
}
dfs2(1,0);
dfs3(1,0,0);
LL ans = ~0U>>1;
for (int i = 1; i <= n; i++) ans = min(ans,g[i]);
cout << ans;
return 0;
}
T3:
枚举出所有合法的最小单元,设有cnt个
每个方案等价于对这cnt个单元的一种分割
间隔中可以选择割或者不割
ans = 2^(cnt-1)
不贴代码了。。。(这题重要的是思路(IQ)思路(IQ)啊)