http://acm.fzu.edu.cn/problem.php?pid=2066
题意:给一个线路板,分为左边和右边,各N个点,然后给出M条连线(左边和右边),问两两相交的线最多有几个。
解法:
比如:
1 2 3 4
1’ 2‘ 3’ 4‘
然后4‘ 连着2,3’连着3,2‘连着4,怎么做呢?先看4连着2’,再看3连着3‘,2连着4’;这样是不是就是在一个序列(2‘,3’,4‘)里找到一个最大上升子序列的问题吗?
ps:不能只找最小的点,开始时我就是这样WA了,应该将所有的点搞一下。
#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int maxn = 100005;
struct edge{
int x,y;
};
edge e[maxn];
int c[maxn];
const int inf = 0x3f3f3f3f;
bool cmp(edge a,edge b){
return a.x == b.x ? a.y > b.y : a.x > b.x;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=-1){
for(int i=0;i<m;i++){
int t,x;
scanf("%d%d",&e[i].x,&e[i].y);
}
sort(e,e + m,cmp);
int len = 1;
c[0] = inf;
for(int i=0;i<m;i++){
int t = lower_bound(c,c+len,e[i].y)-c;
c[t] = e[i].y;
if(t == len)len ++;
}
printf("%d\n",len);
}
return 0;
}
http://acm.fzu.edu.cn/problem.php?pid=2069
题意:一棵树,让你删M个节点,最后保证还是连通的,每个节点有对应的产值O和污染P,最后求最大的sum(O)/sum(P);
树形dp,一开始不知道怎么Dp,囧~
二分答案,为什么可以二分呢?
ans = sum(Oi)/sum(Pi);
设 x <= ans,即
sum(Oi)- x * sum(pi)>= 0;
这样我们就可以对sum(Oi)- x * sum(pi)这个值进行操作了
这样就把除法转化为了减法,是不是很神奇!
#include <cstdio>
#include <deque>
#include <set>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn = 105;
#define eps 1e-6
#define inf 1e10
int n,m;
int o[maxn];
int p[maxn];
int deg[maxn];
int S;
struct node
{
int to;
int next;
}e[maxn*2];
int head[maxn];
int tot;
double dp[maxn][maxn];
double xx;
template<class T> inline void checkmax(T &a, T b){if(b > a) a = b;}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
//memset(dp,0,sizeof(dp));
memset(deg,0,sizeof(deg));
}
void addedge(int u, int v)
{
e[tot].to = v;
e[tot].next = head[u];
head[u] = tot ++;
}
void dfs(int u, int pre)
{
dp[u][1] = 1.0*o[u] - xx*p[u];
for(int i=head[u];i!=-1;i=e[i].next){
int v = e[i].to;
if(v == pre)continue;
dfs(v,u);
for(int j=m;j>=0;j--){
for(int k=0;k<=j;k++){
dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]);
}
}
}
}
bool check(double x){
xx = x;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
dp[i][j] = -inf;
}
}
dfs(S,0);
for(int i=1;i<=n;i++){
if(dp[i][m]>=0)return true;
}
return false;
}
int main(){
while(scanf("%d%d",&n,&m)!=-1){
m = n - m;
for(int i=1;i<=n;i++)scanf("%d",&o[i]);
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
init();
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
deg[u] ++;
deg[v] ++;
}
for(int i=1;i<=n;i++){
if(deg[i] == 1){
S = i;
break;
}
}
double l = 0,r = 10000000000.0f,ans=0;
while(r-l >= eps){
double m = (l+r)/2;
if(check(m)){
l = m;
ans = m;
}
else r = m;
}
printf("%.1lf\n",ans);
}
return 0;
}