全是憨批题的专题
可能是为了在并查集之后给人恢复信心
简略写一下
模板题,把字母转化为数字
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,a[5005],ans,cnt,num;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v,w;
}e[200005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+num,cmp);
for(int i=1;i<=num;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans+=e[i].w;
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++){
a[i]=i;
}
if(n==0)break;
memset(e,0,sizeof(e));
char u[5],v[5];
int t,w;
num=0,cnt=0;
ans=0;
for(int i=1;i<=n-1;i++){
scanf("%s%d",u,&t);
for(int j=1;j<=t;j++){
scanf("%s%d",v,&w);
e[++num].u=u[0]-'A'+1;
e[num].v=v[0]-'A'+1;
e[num].w=w;
}
}
krus();
cout<<ans<<endl;
}
return 0;
}
模板题
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,a[5005],ans,cnt,num;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v,w;
}e[200005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+m,cmp);
for(int i=1;i<=m;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans+=e[i].w;
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++){
a[i]=i;
}
if(n==0)break;
memset(e,0,sizeof(e));
cin>>m;
num=0,cnt=0;
ans=0;
for(int i=1;i<=m;i++){
e[i].u=read();
e[i].v=read();
e[i].w=read();
}
krus();
cout<<ans<<endl;
}
return 0;
}
三维欧几里得距离,如果距离小于r1+r2则为0,否则减去
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,a[5005];
double ans,cnt;
int num;
double juli(double x1,double y1,double z1,double x2,double y2,double z2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
}
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct node{
double x,y,z,r;
}pos[1005];
struct edge{
int u,v;
double w;
}e[200005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+num,cmp);
for(int i=1;i<=num;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans+=e[i].w;
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++){
a[i]=i;
}
if(n==0)break;
memset(e,0,sizeof(e));
num=0,cnt=0;
ans=0;
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&pos[i].x,&pos[i].y,&pos[i].z,&pos[i].r);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
e[++num].u=i;
e[num].v=j;
double w=juli(pos[i].x,pos[i].y,pos[i].z,pos[j].x,pos[j].y,pos[j].z);
if(w<=pos[i].r+pos[j].r)w=0;
else w-=pos[i].r+pos[j].r;
e[num].w=w;
}
}
krus();
printf("%.3f\n",ans);
}
return 0;
}
给个距离矩阵,再给已有的边,直接把已有的加入并查集或者距离设置为0都可
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace std;
int n,m,a[5005],ans,cnt,num;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v,w;
}e[200005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+num,cmp);
for(int i=1;i<=num;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans+=e[i].w;
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int w;
w=read();
if(j>i){
e[++num].u=i;
e[num].v=j;
e[num].w=w;
}
}
}
m=read();
for(int i=1;i<=m;i++){
int x,y;
x=read(),y=read();
hb(x,y);
}
krus();
cout<<ans;
return 0;
}
边权加上两点点权
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace std;
int n,m,a[5005],ans,cnt,num,cost[5005];
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v,w;
}e[200005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+num,cmp);
for(int i=1;i<=num;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans+=e[i].w;
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
int t;
t=read();
while(t--){
n=read();
num=0,ans=0,cnt=0;
memset(e,0,sizeof(e));
for(int i=1;i<=n;i++){
a[i]=i;
}
for(int i=1;i<=n;i++){
cost[i]=read();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int w;
w=read();
if(j>i){
e[++num].u=i;
e[num].v=j;
e[num].w=w+cost[i]+cost[j];
}
}
}
krus();
cout<<ans<<endl;
}
return 0;
}
两个字符串中不同字符的数量为权,稠密图,适合prim,特意学了一下堆优化prim
之前对vector用memset一直MLE后来换了clear才过,才知道不能对vector和string用memset,会发生内存泄漏,记住!
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int k,n,m,cnt,ans,sum;
int dis[2005],vis[2005];
struct edge{
int v,w;
};
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
vector<edge>g[2005];
priority_queue<node>q;
void prim(){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1]=0;
q.push((node){0,1});
while(!q.empty()&&cnt<n){
node x=q.top();
q.pop();
int d=x.w;
int u=x.now;
if(vis[u])continue;
cnt++;
sum+=d;
vis[u]=1;
for(int i=0;i<g[u].size();i++){
if(g[u][i].w<dis[g[u][i].v]){
dis[g[u][i].v]=g[u][i].w;
q.push((node){dis[g[u][i].v],g[u][i].v});
}
}
}
while(!q.empty())q.pop();
return;
}
string a[2005];
int getd(int i,int j){
int c=0;
for(int x=0;x<7;x++){
if(a[i][x]!=a[j][x])c++;
}
return c;
}
int main(){
while(cin>>n){
if(n==0)break;
cnt=0,sum=0,ans=0;
// memset(g,0,sizeof(g));
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++)
{
int w=getd(i,j);
g[i].push_back((edge){j,w});
g[j].push_back((edge){i,w});
}
}
prim();
if(cnt==n)printf("The highest possible quality is 1/%d.\n",sum);
for(int i=1;i<=n;i++){
g[i].clear();
}
}
return 0;
}
最小生成树的最大边
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v;
double w;
}e[1000005];
struct node{
double x,y;
}pos[1000005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+bs,cmp);
for(int i=1;i<=bs;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans=max(ans,e[i].w);
hb(u,v);
if(++cnt==n-m)break;
}
}
int main(){
int tt;
cin>>tt;
while(tt--){
m=read(),n=read();
for(int i=1;i<=n;i++){
a[i]=i;
}
cnt=0,ans=0,bs=1;
for(int i=1;i<=n;i++){
pos[i].x=read();
pos[i].y=read();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
e[bs].u=i;
e[bs].v=j;
e[bs].w=(double)sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x)+(pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
bs++;
}
}
krus();
printf("%.2f\n",ans);
}
return 0;
}
给一些权为0的边,求最小生成树中非0边的连接的端点
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
double juli(double x1,double y1,double x2,double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v;
double w;
}e[1000005];
struct node{
double x,y;
}pos[1000005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+bs,cmp);
for(int i=1;i<=bs;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
if(e[i].w!=0){
printf("%d %d\n",u,v);
}
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=i;
}
cnt=0,ans=0,bs=1;
for(int i=1;i<=n;i++){
pos[i].x=read();
pos[i].y=read();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
e[bs].u=i;
e[bs].v=j;
e[bs].w=juli(pos[i].x,pos[i].y,pos[j].x,pos[j].y);
bs++;
}
}
m=read();
for(int i=1;i<=m;i++){
e[bs].u=read();
e[bs].v=read();
e[bs].w=0;
bs++;
}
krus();
return 0;
}
跟前面某题一样的模板题
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace std;
int n,m,a[5005],ans,cnt,num,cost[5005];
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
struct edge{
int u,v,w;
}e[200005];
int find(int x){
if(a[x]==x)return x;
return a[x]=find(a[x]);
}
void hb(int y,int x){
a[find(y)]=find(x);
return;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void krus(){
sort(e+1,e+1+num,cmp);
for(int i=1;i<=num;i++){
int u,v;
u=e[i].u;
v=e[i].v;
if(find(u)==find(v))continue;
ans+=e[i].w;
hb(u,v);
if(++cnt==n-1)break;
}
}
int main(){
while(cin>>n){
num=0,ans=0,cnt=0;
memset(e,0,sizeof(e));
for(int i=1;i<=n;i++){
a[i]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int w;
w=read();
if(j>i){
e[++num].u=i;
e[num].v=j;
e[num].w=w;
}
}
}
krus();
cout<<ans<<endl;
}
return 0;
}
每个点都能作为出发点,bfs每个点到其他点的距离建边
次小生成树模板题
#include
#include
#include
#include
#include
using namespace std;
const int inf =0x3f3f3f3f;
int n,m;
struct node{
int u,v,w;
int vis;
}e[20010];
vector<int>g[110];
int f[105],maxx[105][105];
bool cmp(node a,node b){
return a.w<b.w;
}
int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
void krus(){
sort(e+1,e+1+m,cmp);
for(int i=0;i<=n;i++){
g[i].clear();
g[i].push_back(i);
f[i]=i;
}
int sum=0,cnt=0;
for(int i=1;i<=m;i++){
if(cnt==n-1)break;
int u=e[i].u;
int v=e[i].v;
if(find(u)==find(v))continue;
u=find(u);
v=find(v);
e[i].vis=1;
cnt++;
sum+=e[i].w;
for(int j=0;j<g[u].size();j++){
for(int k=0;k<g[v].size();k++){
maxx[g[u][j]][g[v][k]]=maxx[g[v][k]][g[u][j]]=e[i].w;
}
}
f[find(u)]=find(v);
for(int j=0;j<g[u].size();j++){
g[v].push_back(g[u][j]);
}
}
int ss=inf;
for(int i=1;i<=m;i++){
if(!e[i].vis){
ss=min(ss,sum+e[i].w-maxx[e[i].u][e[i].v]);
}
}
if(ss>sum){
printf("%d\n",sum);
}
else printf("Not Unique!\n");
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
e[i].vis = 0;
}
krus();
}
return 0;
}
纯模板
跟T1一样
跟之前给坐标求距离的题一样
这个专题很快速的搞完了
接着弄完生成树专题,然后
六月
打算搞一整个月数论和DP,虽然以后我不负责这一块,但是至少要会基础内容,不然队友卡了的时候我都不能提供思路