P1892 [BOI2003]团伙
数组记录敌人;且在每次合并前,先合并别人的敌人
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e4+5;
int p[maxn],f[maxn],n,m;
int r_find(int r)
{
if(f[r]==r)
return r;
f[r]=r_find(f[r]);
return f[r];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++)
{
char c;int a,b;
cin>>c>>a>>b;
if(c=='F')
{
int fx=r_find(a),fy=r_find(b);
f[fx]=fy;
}
if(c=='E')
{
if(p[a])
{
int fx=r_find(p[a]),fy=r_find(b);
f[fx]=fy;
}
if(p[b])
{
int fx=r_find(a),fy=r_find(p[b]);
f[fx]=fy;
}
p[a]=b,p[b]=a; //存储敌人
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(f[i]==i) ans++;
}
cout<<ans<<endl;
return 0;
}
P1955 [NOI2015] 程序自动分析
离散化处理+并查集。。。。思路是不难,但这离散化处理确实麻烦
1.进行排序,然后去重。
2.lowerbound进行下标的查找
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
int f[maxn],book[maxn*3],n,m;
struct node
{
int x,y,z;
}e[maxn];
bool cmp(node e1,node e2)
{
return e1.z>e2.z;
}
int r_find(int r)
{
if(f[r]==r)
return r;
f[r]=r_find(f[r]);
return f[r];
}
signed main()
{
int t;cin>>t;
while(t--)
{
int tol=0;cin>>n;
memset(book,0,sizeof(book));
for(int i=1;i<=n;i++){
cin>>e[i].x>>e[i].y>>e[i].z;
book[++tol]=e[i].x,book[++tol]=e[i].y;
}
sort(book+1,book+tol+1);
int cnt=unique(book+1,book+tol+1)-book-1;
for(int i=1;i<=n;i++)
{
e[i].x=lower_bound(book+1,book+cnt+1,e[i].x)-book;
e[i].y=lower_bound(book+1,book+cnt+1,e[i].y)-book;
}
for(int i=1;i<=cnt;i++) f[i]=i;
int flag=1;
sort(e+1,e+n+1,cmp);
for(int i=1;i<=n;i++)
{
int fx=r_find(e[i].x),fy=r_find(e[i].y);
if(e[i].z==1)
f[fx]=fy;
else if(e[i].z==0)
{
if(fx==fy)
{
cout<<"NO"<<endl;flag=0;break;
}
}
}
if(flag)
cout<<"YES"<<endl;
}
return 0;
}
P1991 无线通讯网
主要是对于电话的处理。共p个灯塔,需要p-1条边,最后的(s-1)个边放电话。
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
int f[maxn],s,p,a[maxn],b[maxn],cnt;
struct node
{
int x,y;double dis;
}e[maxn];
bool cmp(node e1,node e2)
{
return e1.dis<e2.dis;
}
int r_find(int r)
{
if(f[r]==r)
return r;
f[r]=r_find(f[r]);
return f[r];
}
double cal(int x1,int y1,int x2,int y2)
{
return (double)sqrt((x1-x2)*(x1-x2)*1.0+(y1-y2)*(y1-y2)*1.0);
}
signed main()
{
scanf("%d%d",&s,&p);
for(int i=1;i<=p;i++)
scanf("%d%d",&a[i],&b[i]);
for(int i=1;i<p;i++)
for(int j=i+1;j<=p;j++)
{
e[++cnt].x=i,e[cnt].y=j,e[cnt].dis=cal(a[i],b[i],a[j],b[j]);
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=p;i++) f[i]=i;
int ans=0;
for(int i=1;i<=cnt;i++)
{
int fx=r_find(e[i].x),fy=r_find(e[i].y);
if(fx!=fy)
{
f[fx]=fy;ans++;
if(ans>=(p-1)-(s-1))
{
ans=i;break;
}
}
}
cout<<fixed<<setprecision(2)<<e[ans].dis<<endl;
return 0;
}
背包
举例:10000个物品利用二进制优化,拆分成1,2,4,8,16,32,64,128……个,剩下的不满则10000去减。
int t=1;
while(x>=t)
{
v[cnt]=a*t;
c[cnt++]=b*t;
x-=t;t<<=1;
}
if(x)
{
v[cnt]=a*x;
b[cnt++]=b*x;
}
P2170 选学霸
难点在于背包的处理。
记得学一下bitset优化的01背包!!!
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
int f[maxn],n,m,k,sz[maxn],p[maxn],cnt,dp[maxn];
int r_find(int r)
{
if(f[r]==r)
return r;
f[r]=r_find(f[r]);
sz[r]=sz[f[r]];
return f[r];
}
signed main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++) f[i]=i,sz[i]=1;
for(int i=1;i<=k;i++)
{
int a,b;cin>>a>>b;
int fx=r_find(a),fy=r_find(b);
if(fx!=fy)
{
f[fx]=fy;
sz[fx]+=sz[fy];
sz[fy]=sz[fx];
}
}
for(int i=1;i<=n;i++)
{
if(f[i]==i)
{
p[++cnt]=sz[i];
}
}
dp[0]=true;
for(int i=1; i<=cnt; i++)
for(int j=n; j>=p[i]; j--)
if(!dp[j]&&dp[j-p[i]])
dp[j]=true;
int ans=inf,minn=inf;
for(int i=0; i<=n; i++)
if(dp[i]&&abs(i-m)<minn) minn=abs(i-m),ans=i;
cout<<ans<<endl;
return 0;
}