Sightseeing Cows
首先,我们要明白,这道题可能有负环,因此,我们要用SPFA来做,别问,问就是不会,然后可以二分,因为是个0/1分数规划,所以对于任意的环,求出一个mid并且判断二者关系后就可以二分了。
**注意!!!**每次我们要建一个新图跑SPFA求最短路。(在pd()里面)
#include<bits/stdc++.h>
#define N 1006
#define M 5006
#define eps 1e-6
using namespace std;
int n,m,c[N],f[N],x[M],y[M],z[M];
int head[N],to[M],nex[M],tot;//建图
double val[M],d[N];
bool v[N];
void add(int x,int y,double z){
to[++tot]=y;
nex[tot]=head[x];
head[x]=tot;
val[tot]=z;
}
bool spfa(){
queue<int>q;//队列
for (int i = 1; i <= n; i++) {
q.push(i);
d[i]=0;//长度
v[i]=1;//是否在队列中
}
memset(c, 0, sizeof(c));
while (q.size()){
int x = q.front();
q.pop();
v[x] = 0;
for (int i=head[x];i;i=nex[i]){
int y=to[i];
if (d[y] > d[x] + val[i]) {
d[y] = d[x] + val[i];
if(++c[y]>n)return 1;
if(!v[y]){
q.push(y);
v[y]=1;
}
}
}
}
return 0;
}
bool pd(double w) {
tot=0;
memset(head, 0, sizeof(head));
for(int i=1;i<=m;i++)add(x[i],y[i],w*z[i]-f[x[i]]);
return spfa();
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)scanf("%d", &f[i]);
for (int i=1;i<=m;i++)scanf("%d%d%d",&x[i],&y[i],&z[i]);
double l=0,r=1000;
while(r-l>eps){
double mid=(l+r)/2;
if(pd(mid))l=mid;
else r=mid;
}
printf("%.2f",l);
return 0;
}
银河英雄传说
莱因哈特为什么不直接干呢,一看就知道是并查集,但是跟普通的不太一样,因此在merge和get函数里面要加点东西记录位置和长度,就用size存大小,d存位置,就好了
还有一点,root是不能省的,因为要存初始状态,不然就存了个寂寞,都在code里了
#include<bits/stdc++.h>
#define N 30001
using namespace std;
int n,fa[N],d[N],size[N],l,r;
char opt[2];
int get(int x){
if(fa[x]==x)return x;
int root=get(fa[x]);//这里要存初始状态,不然就要W掉90%
d[x]+=d[fa[x]];//求边权
return fa[x]=root;
}
void merge(int x,int y){//合并x到y
x=get(x),y=get(y);
fa[x]=y,d[x]=size[y];
size[y]+=size[x];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=N;i++)fa[i]=i;
for(int i=1;i<=N;i++)size[i]=1;
while(n--){
scanf("%s%d%d",opt,&l,&r);
if(opt[0]=='M')merge(l,r);
else {
if(get(l)!=get(r))printf("-1\n");
else printf("%d\n",abs(d[l]-d[r])-1);
}
}
}
搭配购买(buy)
!背包!,嗯……还有并查集!,简直不要太简单,把要存到一起的合并了就OK,不过要判断他们是不是本来就在一起,然后就好了。
#include<bits/stdc++.h>
#define N 10001
#define INF 100000
using namespace std;
int n,m,fa[N],w1[N],w2[N],l,r,tot=0,w,val1[N],val2[N];
int f[N];
int get(int x){
return fa[x]==x?x:fa[x]=get(fa[x]);//路径压缩
}
void merge(int x,int y){//合并x到y
fa[y]=x,w1[x]+=w1[y],val1[x]+=val1[y];
// w1[y]=INF,val1[y]=0;
}
int main(){
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=n;i++)scanf("%d%d",&w1[i],&val1[i]);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
l=get(l),r=get(r);
if(l==r)continue;
merge(l,r);
}
memset(f,0xcf,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++){
if(fa[i]==i)
for(int j=w;j>=w1[i];j--){
f[j]=max(f[j],f[j-w1[i]]+val1[i]);
}
}
int ans=0;
for(int i=0;i<=w;i++)ans=max(ans,f[i]);
printf("%d",ans);
}
溜溜球。