写之前先给这个专题做个总结
知识点:单源最短路,全源最短路,求最短路中的最长边,bellman ford算法求有负权的最短路,bellman or SPFA判断环,反向建图,差分约束,层次图建立层点(连通点)。
应该是覆盖最短路所有内容了
模板题
Floyd模板题,只要看到这个数据范围冲就完事了(n<=800)
题意:求能到达终点的最大边权最小
看题意很明显这个题可以用二分答案做,然而我一直莫名其妙的wa?用最大生成树的最小边也wa,然后换了变形dij才过…
dij的堆要写成大根堆,因为要优先选择边权大,不然会wa
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 200010
#define maxm 200010
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,s,vis[maxn],dis[maxn];
vector<edge>p[100005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w<x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0x3f3f3f3f;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]<min(dis[u],p[u][i].w)){
dis[v]=min(dis[u],p[u][i].w);
q.push((node){dis[v],v});
}
}
}
}
signed main(){
int tt,qq=0;
cin>>tt;
while(tt--){
qq++;
n=read(),m=read();
memset(p,0,sizeof(p));
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p[y].push_back((edge){x,z});
}
dij(1);
printf("Scenario #%d:\n",qq);
printf("%d\n\n",dis[n]);
}
return 0;
}
题意:求所有牛来回party最短路的最大值
见到这种来回的,一般都是直接建反图就完事了
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 200010
#define maxm 200010
const int inf=0x3f3f3f3f;
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,mm,s,vis[maxn],dis[maxn],dis1[maxn],vis1[maxn];
vector<edge>p[100005],p1[100005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
inline void dij(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
inline void dij1(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis1[i]=inf;
}
memset(vis1,0,sizeof(vis1));
dis1[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis1[u])continue;
vis1[u]=1;
for(int i=0;i<p1[u].size();i++){
int v=p1[u][i].v;
if(dis1[v]>dis1[u]+p1[u][i].w){
dis1[v]=dis1[u]+p1[u][i].w;
q.push((node){dis1[v],v});
}
}
}
}
signed main(){
n=read(),m=read(),s=read();
mm=0;
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p1[y].push_back((edge){x,z});
}
for(int i=1;i<=n;i++){
if(i==s)continue;
dij(i);
dij1(i);
mm=max(mm,dis[s]+dis1[s]);
// cout<
}
cout<<mm;
return 0;
}
读题难度>解题难度
判环模板题
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,cnt,ans,c=1;
double r1,r2,c1,c2;
int k;
double money;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int u,v;
double r,c;
};
vector<edge>e;
double d[1005];
bool bellman(){
memset(d,0,sizeof(d));
d[k]=money;
for(int i=1;i<n;i++){
int ok=0;
for(int j=0;j<e.size();j++){
if((d[e[j].u]-e[j].c)*e[j].r>d[e[j].v]){
d[e[j].v]=(d[e[j].u]-e[j].c)*e[j].r;
ok=1;
}
}
if(!ok)break;
}
for(int i=0;i<e.size();i++){
if((d[e[i].u]-e[i].c)*e[i].r>d[e[i].v]){
return true;
}
}
return false;
}
signed main(){
cin>>n>>m>>k>>money;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y>>r1>>c1>>r2>>c2;
e.push_back((edge){x,y,r1,c1});
e.push_back((edge){y,x,r2,c2});
}
if(bellman())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
判环,比上一题还简单,故略
读入难度>>解题难度
读x的时候一定要注意这个坑…用string的话会出问题
读入完直接跑Floyd就没了
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,w,cnt,ans,c=1;
int dis[105][105];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)dis[i][j]=0;
else dis[i][j]=inf;
}
}
for(int i=2;i<=n;i++){
for(int j=1;j<=i-1;j++){
char x[50];
scanf("%s",x);
if(x[0]=='x'){
continue;
}
else{
int k=atoi(x);
dis[i][j]=k;
dis[j][i]=k;
}
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
int mm=0;
for(int i=2;i<=n;i++){
if(dis[1][i]!=inf){
mm=max(mm,dis[1][i]);
}
}
cout<<mm<<endl;
return 0;
}
给出一些列大小关系,问有多少头牛的排名可以确定
思路其实很简单,以大小关系建立单向边,跑一遍Floyd,求出来dis[i][j]的值不为inf就cnt[i] ,cnt[j]都+1,统计完之后如果值为n-1就代表跟所有其他的牛都有确定大小关系,即为答案
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,t,ans,mxn;
int dis[505][505],vis[505][505],cnt[505];
int main(){
cin>>n>>m;
memset(dis,inf,sizeof(dis));
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
dis[x][y]=1;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
if(dis[i][j]!=inf)cnt[j]++,cnt[i]++;
}
}
for(int i=1;i<=n;i++){
if(cnt[i]==n-1)ans++;
}
cout<<ans;
return 0;
}
套利,判环,这题之前在洛谷上面做过,用map乱搞,跑Floyd判断是否有dis最终大于1,有就是有环,然而交vj直接给我TLE,换成bellman 判环 TLE,(poj懂的都懂好吧)没有氧气优化又没有C++11真的吐了,傻逼测评姬
最终 SPFA判环可过
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,f;
double dis[50][50];
string a;
map<string,int>m;
double s;
string x,y;
struct edge{
int v;
double w;
};
vector<edge>e[5005];
double d[1005];
int cnt[10050];
int vis[10050];
bool spfa(){
int ct=0;
memset(cnt,0,sizeof(cnt));
queue<int>q;
for(int i=1;i<=n;i++){
d[i]=1;
vis[i]=1,
q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].v;
double w=d[u]*e[u][i].w;
if(d[v]<w){
d[v]=w;
cnt[v]=cnt[u]+1;
if(ct>4*n)return true;
if(cnt[v]>=n)return true;
if(vis[v]==0)q.push(v),vis[v]=1;
}
}
}
return false;
}
int main(){
while(1){
int t;
f++;
cin>>t;
if(t==0)break;
m.clear();
memset(e,0,sizeof(e));
for(int i=1;i<=t;i++){
cin>>a;
m[a]=i;
}
cin>>n;
for(int i=1;i<=n;i++){
double z;
cin>>x>>z>>y;
e[m[x]].push_back((edge){m[y],z});
}
if(spfa())printf("Case %d: Yes\n",f);
else printf("Case %d: No\n",f);
}
return 0;
}
UVA721
在vj上面一直wa,为了验证我的程序是对的,特意注册账号去UVA交了原题,AC了,poj爬
思路:建反图
(本代码在vj上过不了)
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 1000010
#define maxm 1000010
const int inf=0x3f3f3f3f;
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,mm,s,vis[maxn],dis[maxn],dis1[maxn],vis1[maxn];
vector<edge>p[1000005],p1[1000005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
inline void dij(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
inline void dij1(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis1[i]=inf;
}
memset(vis1,0,sizeof(vis1));
dis1[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis1[u])continue;
vis1[u]=1;
for(int i=0;i<p1[u].size();i++){
int v=p1[u][i].v;
if(dis1[v]>dis1[u]+p1[u][i].w){
dis1[v]=dis1[u]+p1[u][i].w;
q.push((node){dis1[v],v});
}
}
}
}
signed main(){
int tt;
cin>>tt;
while(tt--){
n=read(),m=read();
mm=0;
memset(p,0,sizeof(p));
memset(p1,0,sizeof(p1));
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p1[y].push_back((edge){x,z});
}
dij(1);
dij1(1);
for(int i=2;i<=n;i++){
mm+=dis[i]+dis1[i];
}
cout<<mm<<endl;
}
return 0;
}
差分约束,太水了,甚至不能算模板,直接用dij建单边就过了
模板在后面
此题难点在于建图,建图难度>>解题难度
对每个相间车站建直线距离边,再对所有点建欧几里得距离边,最后跑一遍dij
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v;
double w;
}e[maxm];
int num;
int cnt,n,m,s,vis[maxn];
double dis[maxn];
vector<edge>p[100005];
struct node{
double w;
int now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
for(int i=1;i<=num;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
double juli(double x1,double y1,double x2,double y2,double tt){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))/tt/1000*60;
}
struct ta{
double x,y;
}stop[505];
int sx,sy,dx,dy;
int main(){
sx=read(),sy=read(),dx=read(),dy=read();
stop[1].x=sx;
stop[1].y=sy;
memset(dis,0x3f3f3f3f,sizeof(dis));
int x,y;
num=2;
while(~scanf("%d%d",&x,&y)){
stop[num].x=x,stop[num].y=y;
int xx,yy;
while(~scanf("%d%d",&xx,&yy)){
if(xx==-1&&yy==-1)break;
stop[num+1].x=xx;
stop[num+1].y=yy;
double d=juli(x,y,xx,yy,40);
p[num].push_back((edge){num+1,d});
p[num+1].push_back((edge){num,d});
x=xx;
y=yy;
num++;
}
num++;
}
stop[num].x=dx;
stop[num].y=dy;
for(int i=0;i<=num;i++){
for(int j=0;j<=num;j++){
if(i==j)continue;
double d=juli(stop[i].x,stop[i].y,stop[j].x,stop[j].y,10);
p[i].push_back((edge){j,d});
}
}
dij(1);
printf("%.f",dis[num]);
return 0;
}
此题的题意真的是坑的让人吐血…最开始理解成探险家最开始等级无限,接触一个人之后就降等,降等之后不能跟高级商家交易,结果真正的题意是:探险家接触过的所有人的等级差距都不能超过m
比如酋长的等级是5,m是2,你最开始跟等级7的人交易过,你就不能再跟<5的人交易了,所有其实是询问长度为m的一个区间(并且酋长的等级一定要包含在区间内),一共跑m+1次dij,建图很简单,每个物品从0向它建一条原价边,再从它的前置物建优惠边即可
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
#define int long long
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w,dengji;
}e[maxm];
int cnt,n,m,s,vis[maxn],dis[maxn];
vector<edge>p[100005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s,int dj1,int dj2){
for(int i=1;i<=n;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[0]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w&&p[u][i].dengji>=dj1&&p[u][i].dengji<=dj2){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
signed main(){
m=read(),n=read();
int zui;
for(int i=1;i<=n;i++){
int money,dj,q;
money=read(),dj=read(),q=read();
if(i==1)zui=dj;
p[0].push_back((edge){i,money,dj});
for(int j=1;j<=q;j++){
int x,y;
x=read(),y=read();
p[x].push_back((edge){i,y,dj});
}
}
int qq=m;
int mm=0x3f3f3f3f;
for(int i=1;i<=m+1;i++){
dij(0,zui-qq,zui-qq+m);
// cout<
qq--;
mm=min(dis[1],mm);
}
cout<<mm;
return 0;
}
每个车站第一条边权为0,其他为1,然后就是Floyd傻逼题了
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
int dis[105][105];
int a,b,n;
int m;
signed main(){
cin>>n>>a>>b;
memset(dis,inf,sizeof(dis));
for(int i=1;i<=n;i++){
int t;
cin>>t;
for(int j=1;j<=t;j++){
int x;
x=read();
if(j==1)dis[i][x]=0;
else dis[i][x]=1;
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
/// cout<
// }
// cout<
// }
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
if(dis[a][b]!=inf)cout<<dis[a][b];
else cout<<"-1";
return 0;
}
三次方会出负数…spfa判环
询问的点不在环上且可到达输出距离,否则直接疑惑
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
int d[5005];
int n,a[5005],q[5005];
int m,vis[5005],cs[5005];
struct edge{
int v,w;
};
vector<edge>e[5005];
void spfa(){
memset(d,inf,sizeof(d));
memset(vis,0,sizeof(vis));
memset(cs,0,sizeof(cs));
queue<int>q;
d[1]=0;
cs[1]=1;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].v;
int w=e[u][i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(vis[v]==0&&cs[v]<=n){
cs[v]++;
q.push(v);
vis[v]=1;
}
}
}
}
}
signed main(){
int tt,qq=0,p;
cin>>tt;
while(tt--){
cin>>n;
qq++;
for(int i=1;i<=n;i++){
a[i]=read();
}
cin>>m;
for(int i=1;i<=m;i++){
int u,v;
u=read(),v=read();
int dis=(a[v]-a[u])*(a[v]-a[u])*(a[v]-a[u]);
e[u].push_back((edge){v,dis});
}
cin>>p;
for(int i=1;i<=p;i++){
q[i]=read();
}
spfa();
printf("Case %d:\n",qq);
for(int i=1;i<=p;i++){
if(d[q[i]]<3||d[q[i]]>=inf||cs[q[i]]>n){
printf("?\n");
}
else{
printf("%d\n",d[q[i]]);
}
}
memset(e,0,sizeof(e));
}
return 0;
}
建图题
每个点有它所属的层,层之间有通道,对层之间所有点全部建边肯定会炸,所以建立每一层的层点,即专门用来连接属于这一层其他点的点
#include
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,c,vis[maxn],dis[maxn];
vector<edge>p[200005];
int cs[200005],layer[200005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
signed main(){
int tt;
cin>>tt;
for(int rr=1;rr<=tt;rr++){
n=read(),m=read(),c=read();
for(int i=1;i<=n;i++){
layer[i]=read();
cs[layer[i]]=1;
}
for(int i=1;i<=n;i++){
p[layer[i]+n].push_back((edge){i,0});
if(layer[i]-1>=1&&cs[layer[i]-1]==1){
p[i].push_back((edge){layer[i]-1+n,c});
}
if(layer[i]+1<=n&&cs[layer[i]+1]==1){
p[i].push_back((edge){layer[i]+1+n,c});
}
}
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p[y].push_back((edge){x,z});
}
// cout<
// for(int i=1;i<=n;i++){
// for(int j=0;j
// printf("%d %d %d\n",i,p[i][j].v,p[i][j].w);
// }
// }
dij(1);
if(dis[n]==inf)printf("Case #%d: -1\n",rr);
else printf("Case #%d: %d\n",rr,dis[n]);
memset(layer,0,sizeof(layer));
memset(cs,0,sizeof(cs));
memset(p,0,sizeof(p));
}
return 0;
}
网络流,待补
这题必须配放个图
此题是我有史以来读过题意最抽象的题目,没有之一,读了两个小时没读懂
题目给了一些条件和一个矩阵,要你求一个矩阵使两个矩阵对应点乘积和最小
思维转化,给出的条件代表点1的出度为1,点n的入度为1,其他的所有点出入度相等,路径长度非负,还有两种特殊情况,图中有从1 or n出发的环,这样的情况下其他的点入度出度全为0,也符合题目的条件
拿dij跑最短路,并判断特殊情况
#include
#include
#include
#include
using namespace std;
int n,m,a[305][305],d[305];
const int inf=0x3f3f3f3f;
int ans,h;
int vis[350];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
void dij(int s){
memset(d,inf,sizeof(d));
memset(vis,false,sizeof(vis));
d[s]=0;
for(int i=1;i<=n;i++){
int t=-1;
for(int j=1;j<=n;j++){
if(vis[j]==false&&(t==-1||d[t]>d[j])){
t=j;
}
}
vis[t]=true;
for(int j=1;j<=n;j++){
d[j]=min(d[j],d[t]+a[t][j]);
if(j==s&&t!=s)h=min(h,d[t]+a[t][j]);
}
}
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=read();
}
}
h=inf;
dij(1);
ans=d[n];
int t=h;
h=inf;
dij(n);
t+=h;
cout<<min(ans,t)<<endl;
}
}
差分约束模板来了
白书上经典例题
重点在于符号的判断>=和<=是两个方向,并且建立超级源点
建图完跑bellman即可
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,w,cnt,ans;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int u,v,w;
};
vector<edge>e;
int d[1005];
bool bellman(){
memset(d,inf,sizeof(d));
d[1]=0;
for(int i=1;i<n;i++){
int ok=0;
for(int j=0;j<e.size();j++){
edge ee=e[j];
if(d[ee.v]>d[ee.u]+ee.w){
d[ee.v]=d[ee.u]+ee.w;
ok=1;
}
}
if(!ok)break;
}
for(int i=0;i<e.size();i++){
edge ee=e[i];
if(d[ee.v]>d[ee.u]+ee.w){
return true;
}
}
return false;
}
signed main(){
int ml,md;
n=read(),ml=read(),md=read();
for(int i=1;i<=ml;i++){
int u,v,w;
u=read(),v=read(),w=read();
e.push_back((edge){u,v,w});
}
for(int i=1;i<=md;i++){
int u,v,w;
u=read(),v=read(),w=read();
e.push_back((edge){v,u,-w});
}
for(int i=1;i<=n-1;i++){
e.push_back((edge){i+1,i,0});
}
if(bellman())cout<<"-1";
else{
if(d[n]>inf/2){
cout<<"-2";
}
else {
cout<<d[n];
}
}
return 0;
}
由于前天晚上和昨天身体超级难受就慢了一点点…而且最后几个题把我拦住了…所以就花了三天
感觉写一下题解还是挺有用的,真正的理解是能解释给别人听让别人理解(费曼学习法),而且回顾整个专题也可以做一些反思,思考题与题之间的关联和区别,温故知新。
继续保持学习状态,冲!!!
要开始学高数和电路分析了(