拆边的故事
感觉“拆边”这个说法实在不专业啊,但也只能这样了,意思到了就行了。
概述
在图论中,有的时候暴力建边的话,可能会得到一个近似于完全图的图,边数会达到
拆边的原理就是把原来的一条边拆成几条边,这样看似边数变多了,但往往原图里的那些边拆完之后有公共部分,拆出来的边不会特别多,以达到降低复杂度的目的。
目前做到的题目,用到拆边的,一般都是图内节点两两可达,而且边权还是用一些奇怪的公式加上两个点自身具有的一些参数计算出来的,这些情况下就可以拆边。
T1
首先说明题非原创,搬运而来,背景嘛倒是我自己写的。
题目重点就是
解法就是先按x坐标排序,给相邻两个点连一条无向边,边权
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N=200010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline int min(int s1,int s2){
return s1<s2?s1:s2;
}
inline int abs(int s1){
return s1<0?-s1:s1;
}
int m;
struct point{
int num,x,y;
}p[N];
struct edge{
int t,next;
ll v;
}e[N<<3];
int esum,head[N];
inline void add(int fr,int to,int val){
esum++;
e[esum].t=to;
e[esum].v=val;
e[esum].next=head[fr];
head[fr]=esum;
}
inline bool cmp1(point s1,point s2){
return s1.x<s2.x;
}
inline bool cmp2(point s1,point s2){
return s1.y<s2.y;
}
ll dis[N];
bool vis[N];
struct node{
int num;
ll dis;
};
inline bool operator <(node s1,node s2){
return s2.dis<s1.dis;
}
priority_queue<node>q;
signed main(){
read(m);
for(int i=1;i<=m;i++){
p[i].num=i;
read(p[i].x);read(p[i].y);
}
sort(p+1,p+m+1,cmp1);
for(int i=1;i<m;i++){
add(p[i].num,p[i+1].num,p[i+1].x-p[i].x);
add(p[i+1].num,p[i].num,p[i+1].x-p[i].x);
}
sort(p+1,p+m+1,cmp2);
for(int i=1;i<m;i++){
add(p[i].num,p[i+1].num,p[i+1].y-p[i].y);
add(p[i+1].num,p[i].num,p[i+1].y-p[i].y);
}
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
q.push((node){1,0});
while(!q.empty()){
node now=q.top();q.pop();
int wh=now.num;ll nd=now.dis;
if(vis[wh])continue;vis[wh]=true;
for(int i=head[wh],th;i;i=e[i].next){
th=e[i].t;
if(dis[wh]+e[i].v<dis[th]){
dis[th]=dis[wh]+e[i].v;
q.push((node){th,dis[th]});
}
}
}
printf("%lld",dis[m]);
return 0;
}
T2
同样,理论上来说这个图里两两可达,而距离
#include<cstdio>
#include<cstring>
#include<queue>
#define id(s1,s2) (s1*m+s2)
//#define zczc
using namespace std;
const int N=50010;
const int M=52;
const int S=N*M;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
wh*=f;return;
}
inline bool get(){
char w=getchar();
while(w!='0'&&w!='1')w=getchar();
return w=='1';
}
int m,n,a[N],b[M][M];
struct edge{
int t,v,next;
}e[S<<2];
int esum,head[S];
inline void add(int fr,int to,int val){
esum++;
e[esum].t=to;
e[esum].v=val;
e[esum].next=head[fr];
head[fr]=esum;
}
int dis[S];
bool vis[S];
struct node{
int wh,dis;
};
bool operator <(node s1,node s2){
return s2.dis<s1.dis;
}
priority_queue<node>q;
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);read(n);
for(int i=1;i<=m;i++)read(a[i]);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
b[i][j]=get();
}
}
for(int i=1;i<=m;i++)add(id(0,i),id(a[i],i),0);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(b[i][a[j]]){
add(id(i,j),id(0,j),0);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<m;j++){
add(id(i,j),id(i,j+1),1);
add(id(i,j+1),id(i,j),1);
}
}
memset(dis,0x3f,sizeof(dis));
dis[id(0,1)]=0;q.push((node){id(0,1),0});
while(!q.empty()){
int wh=q.top().wh,nd=q.top().dis;q.pop();
if(vis[wh])continue;vis[wh]=true;
for(int i=head[wh],th;i;i=e[i].next){
th=e[i].t;
if(dis[wh]+e[i].v<dis[th]){
dis[th]=dis[wh]+e[i].v;
q.push((node){th,dis[th]});
}
}
}
printf("%d",dis[id(0,m)]>1e8?-1:dis[id(0,m)]);
return 0;
}
一如既往,万事胜意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具