LJOJ 1500:

题目:http://www.docin.com/p-601990756.html

Sol:贪心,从叶子结点往上加入无法传递了,就需要建设。 Dfs返回的是到达叶子节点最多所要的能量,如果大于最大能量就需要建设放大器.

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
const int Maxn=;
using namespace std;
int head[Maxn],vis[Maxn],cnt,Ans,x,v,w,n,Power;
struct EDGE{int to,next,w;}edge[Maxn<<];
inline void Add(int u,int v,int w) {edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w;head[u]=cnt++;}
inline int Max(int x,int y) {return x>y?x:y;}
int Dfs(int u)
{
int Res=; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
if (!vis[edge[i].to])
{
int Tmp=Dfs(edge[i].to);
if (Tmp+edge[i].w>=Power) {if (edge[i].w>Res) Res=edge[i].w; Ans++;}
else if (Tmp+edge[i].w>Res) Res=Tmp+edge[i].w;
}
return Res;
}
int main()
{
scanf("%d",&n); int Mx=;
cnt=; memset(head,-,sizeof(head)); Ans=;
for (int i=;i<=n;i++)
{
scanf("%d",&x);
for (int j=;j<=x;j++)
{
scanf("%d%d",&v,&w);
Add(i,v,w),Add(v,i,w); Mx=Max(Mx,w);
}
}
scanf("%d",&Power);
if (Mx>=Power) {puts("No solution."); return ;}
Dfs();
printf("%d\n",Ans);
return ;
}

C++

LJOJ 1501:

题目描述
  出于最高安全性考虑,司令部采用了特殊的安全操作系统,该系统采用一个特殊的文件系统。在这个文件系统中所有磁盘空间都被分成了相同尺寸的N块,用整数1到N标识。每个文件占用磁盘上任意区域的一块或多块存储区,未被文件占用的存储块被认为是可使用的。如果文件存储在磁盘上自然连续的存储块中,则能被以最快的速度读出。   因为磁盘是匀速转动的,所以存取上面不同的存储块需要的时间也不同。读取磁盘开头处的存储块比读取磁盘结尾处的存储块快。根据以上现象,我们事先将文件按其存取频率的大小用整数1到K标识。按文件在磁盘上的最佳存储方法,1号文件将占用1,,…,S1的存储块,2号文件将占用S1+,S1+,...,S1+S2的存储块,以此类推(Si是被第i个文件占用的存储块的个数)。为了将文件以最佳形式存储在磁盘上,需要执行存储块移动操作。一个存储块移动操作包括从磁盘上读取一个被占用的存储块至内存并将它写入其它空的存储块,然后宣称前一个存储块被释放,后一个存储块被占用。   本程序的目的是通过执行最少次数的存储块移动操作,将文件按最佳方式存储到磁盘上,注意同一个文件的存储块在移动之后其相对次序不可改变。
输入
  每个磁盘说明的第一行包含两个用空格隔开的整数N和K,<=K<=N<=,接下来的K行每行说明一个文件,对第i个文件的说明是这样的:首先以整数Si开头,表示第i个文件的存储块数量,<=Si<=N-K,然后跟Si个整数,每个整数之间用空格隔开,表示该文件按自然顺序在磁盘上占用的存储块的标识。所有这些数都介于1和N之间,包括1和N。   一个磁盘说明中所有存储块的标识都是不同的,并且该盘至少有一个空的存储块。
输出
  对于每一个磁盘说明,只需输出一行句子"We need M move operations",M表示将文件按最佳方式存储到磁盘上所需进行的最少存储块移动操作次数。如果文件已按最佳方式存储,仅需输出“No optimization needed.”。
样例输入 样例输出
We need move operations.

题目

Sol:环需要有多余的一块进行交换,不然会覆盖

 #include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int cnt,mb[],n,k,p,x,v[];
int work(int x)
{
if (mb[x]==x) return ;
int p=x,t=x,tot=;v[p]=;
while ()
{
p=mb[p];
tot++;
if (p!=t && p!= && v[p]) return tot;
v[p]=;
if (p==) return tot-;
if (p==t) return tot+; }
}
int main()
{
scanf("%d%d",&n,&k);
for (int i=;i<=k;i++)
{
scanf("%d",&p);
for (int i=;i<=p;i++)
{
scanf("%d",&x);
mb[++cnt]=x;
}
}
int ans=;
for (int i=;i<=cnt;i++) if (!v[i]) ans+=work(i);
if (ans==) printf("No optimization needed.");
else printf("We need %d move operations.\n",ans);
}

C++

LJOJ 1502:

题目:删去一条边使得最短路最长

Sol:Dij后找到最短路,依次删去最短路上的边进行最短路即可

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#define Pa pair<int,int>
#define mp make_pair
using namespace std;
const int Inf=0x3f3f3f3f;
const int Maxn=;
const int Maxm=;
priority_queue<Pa,vector<Pa>,greater<Pa> > Q;
struct EDGE{int to,next,w;}edge[Maxm<<];
int head[Maxn],Dis[Maxn],vis[Maxn],n,m,u,v,w,cnt,Pre[Maxn],Ans,Ban,Ban_Edge[Maxn];
inline void Add(int u,int v,int w) {edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w; head[u]=cnt++;}
int Dij(int Flag)
{
memset(vis,false,sizeof(vis));
for (int i=;i<=n;i++) Dis[i]=Inf;
Dis[]=; Q.push(mp(,));
while (!Q.empty())
{
int u=Q.top().second; Q.pop();
if (vis[u]) continue; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
if (!vis[edge[i].to] && Dis[edge[i].to]>Dis[u]+edge[i].w && Ban!=i && Ban!=(i^))
{
Dis[edge[i].to]=Dis[u]+edge[i].w;
Q.push(mp(Dis[edge[i].to],edge[i].to));
if (Flag) Pre[edge[i].to]=u,Ban_Edge[edge[i].to]=i;
}
}
return Dis[n];
}
int main()
{
// freopen("c.in","r",stdin);
scanf("%d%d",&n,&m); memset(head,-,sizeof(head));
for (int i=;i<=m;i++) scanf("%d%d%d",&u,&v,&w),Add(u,v,w),Add(v,u,w);
Ban=Inf;
Dij(true); Ans=;
u=n;
while (true)
{
Ban=Ban_Edge[u];
int Tmp=Dij(false);
if (Tmp>Ans) Ans=Tmp;
u=Pre[u];
if (u==) break;
}
printf("%d\n",Ans);
return ; }

C++

LJOJ 1503

题目:经典网络流:Pig

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define Inf 1<<29
using namespace std;
const int Maxn=;
struct node
{
int to,next,w;
}edge[];
int cnt,Level[Maxn<<],pigs[Maxn<<],Q[],head[Maxn<<],n,m,Pre[Maxn<<],limit;
inline void Add(int u,int v,int w)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
edge[cnt].w=w;
head[u]=cnt++;
edge[cnt].to=u;
edge[cnt].next=head[v];
edge[cnt].w=;//写成w
head[v]=cnt++;
} inline int Min(int a,int b){return a>b?b:a;}
bool Bfs()
{
memset(Level,-,sizeof(Level));
int l=,r=;
Q[]=;Level[]=;
while (l<=r)
{
int u=Q[l++];
for (int i=head[u];i!=-;i=edge[i].next)
if (Level[edge[i].to]==- && edge[i].w>)
{
Level[edge[i].to]=Level[u]+;
Q[++r]=edge[i].to;
}
}
if (Level[n+]>) return true;
return false;
} int Find(int u,int low)
{
if (u==n+) return low;
int tmp=;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (edge[i].w>
&& Level[v]==Level[u]+
&& (tmp=Find(v,Min(low,edge[i].w))))
{
edge[i].w-=tmp,edge[i^].w+=tmp;
return tmp;
}
}
Level[u]=-;
return ;
} int main()
{
scanf("%d%d",&m,&n);
memset(Pre,,sizeof(Pre));
memset(head,-,sizeof(head));
cnt=;
for (int i=;i<=m;i++) scanf("%d",&pigs[i]);
for (int i=;i<=n;i++)
{
int tn;
scanf("%d",&tn);
int sum=;
for (int j=;j<=tn;j++)
{
int x;
scanf("%d",&x);
if (Pre[x]==)
sum+=pigs[x]; else
Add(Pre[x],i,Inf);
Pre[x]=i;
}
if (sum!=) Add(,i,sum);
scanf("%d",&limit);
Add(i,n+,limit);
}
int ans=,temp;
while (Bfs())
while (temp=Find(,0x7fffffff))
ans+=temp;
printf("%d\n",ans);
return ;
}

C++

LJOJ 1504

题目: Codevs 3637

Sol:显然不可能形成三角形,假设每点左边的边小于右边的边,会矛盾,然后用Prim就可以了.

 #include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std; const int MAXN=;
const int INF=1e8; struct point{
int x,y;
point(){}
point(int x,int y):x(x),y(y){}
}; int n;
point p[MAXN];
double ans=,d[MAXN];
bool vis[MAXN]={}; double dist(point a,point b){
return sqrt((double)(a.x-b.x)*(double)(a.x-b.x)+(double)(a.y-b.y)*(double)(a.y-b.y));
} int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d%d",&p[i].x,&p[i].y);
d[i]=INF;
}
d[]=;
for(int k,i=;i<=n;i++){
double mi=INF;
for(int j=;j<=n;j++){
if(!vis[j]&&mi>d[j]){
mi=d[j];
k=j;
}
}
if(mi==INF)break;
vis[k]=;
ans+=mi;
for(int j=;j<=n;j++){
if(!vis[j]){
d[j]=min(d[j],dist(p[j],p[k]));
}
}
}
printf("%.2lf\n",ans);
return ;
}

C++

LJOJ 1505

 题目描述
  在这个繁忙的社会中,我们往往不再去选择最短的道路,而是选择最快的路线。开车时每条道路的限速成为最关键的问题。不幸的是,有一些限速的标志丢失了,因此你无法得知应该开多快。一种可以辩解的解决方案是,按照原来的速度行驶。你的任务是计算两地间的最快路线。   你将获得一现代化城市的道路交通信息。为了使问题简化,地图只包括路口和道路。每条道路是有向的,只连接了两条道路,并且最多只有一块限速标志,位于路的起点。两地A和B,最多只有一条道路从A连接到B。你可以假设加速能够在瞬间完成并且不会有交通堵塞等情况会影响你。当然,你的车速不能超过当前的速度限制。
输入
  输入文件SPEED.IN的第一行是3个整数 N,M和D,<=N<=,表示道路的数目,用0..N-1标记。M是道路的总数,D表示你的目的地。接下来的M行,每行描述一条道路,每行有4个整数A ( <= A < N), B ( <= B < N), V ( <= V <= ) and L (<= L <= ),这条路是从A到B的,速度限制是V,长度为L。如果V是0,表示这条路的限速未知。如果V不为0,则经过该路的时间T=L/V。否则T = L / Vold,Vold是你到达该路口前的速度。开始时你位于0点,并且速度为70。
输出
  输出文件SPEED.OUT仅一行整数,表示从0到D经过的城市。输出的顺序必须按照你经过这些城市的顺序,以0开始,以D结束。仅有一条最快路线。
样例输入 样例输出 提示
The required time is in this case , units. 来源

题目

Sol:Bfs记录上次的速度

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#define fi first
#define se second
#define Pa pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
int n,m,T,u,v,Speed,Len,vis[][];
double f[][];
vector<pair<int,pair<int,int> > > E[];
vector<int> Ret;
Pa Pre[][];
int main()
{
scanf("%d%d%d",&n,&m,&T);
for (int i=;i<=m;i++)
{
scanf("%d%d%d%d",&u,&v,&Speed,&Len);
E[u].pb(mp(v,mp(Speed,Len)));
}
queue<Pa> Q;
memset(f,0x7f,sizeof(f));
memset(vis,false,sizeof(vis));
f[][]=,vis[][]=true;
Q.push(mp(,));
while(!Q.empty())
{
Pa u=Q.front(); vis[u.fi][u.se]=; Q.pop();
for (int i=;i<E[u.fi].size();i++)
{
int v=E[u.fi][i].fi,Race=u.se;
if (E[u.fi][i].se.fi!=) Race=E[u.fi][i].se.fi;
if (f[u.fi][u.se]+E[u.fi][i].se.se*1.0/Race<f[v][Race])
{
f[v][Race]=f[u.fi][u.se]+E[u.fi][i].se.se*1.0/Race;
Pre[v][Race]=u;
if (!vis[v][Race])
{
vis[v][Race]=true;
Q.push(mp(v,Race));
}
}
}
}
double Ans=1e30; Pa Opt;
for (int i=;i<=;i++) if (f[T][i]<Ans) Ans=f[T][i],Opt=mp(T,i);
while (Opt.fi!=) Ret.pb(Opt.fi),Opt=Pre[Opt.fi][Opt.se];
printf("0 ");
for (int i=Ret.size()-;i>;i--) printf("%d ",Ret[i]);
printf("%d\n",Ret[]);
}

C++

LJOJ 1506

 题目描述
  你的任务是把一些人分成两组,使得:  •每个人都被分到其中一组;  •每个组都至少有一个人;  •一组中的每个人都认识其他同组成员;  •两组的成员人数尽量接近。  这个问题可能有多个解决方案,你只要输出任意一个即可,或者输出这样的分组法不存在。 输入
  为了简单起见,所有的人都用一个整数标记,每个人号码不同,从1到N。  输入文件的第一行包括一个整数N(≤N≤),N就是需要分组的总人数;接下来的N行对应了这N个人,按每个人号码的升序排列,每一行给出了一串号码Aij (≤Aij≤N,Aij≠i),代表了第i个人所认识的人的号码,号码之间用空格隔开,并以一个“”结束。 输出
  如果分组方法不存在,就输出信息“No solution”(输出时无需加引号)至输出文件;  否则输出两组人数的差的绝对值 样例输入 样例输出

题目

Sol:两个不认识的人肯定不能在一组里,那么就可以相互染色,然后可以分成两块。

 #include <cstdio>
const int Inf=0x3f3f3f3f;
int n,Cnt,Ans;
bool G[][],Tmp[][],F[][];
int vis[],c[],a[],b[],x;
inline int Abs(int x) {return x<?-x:x;}
bool Dfs(int u,int Color)
{
vis[u]=true; c[u]=Color;
for (int i=;i<=n;i++)
{
if (!G[u][i]) continue;
if (c[i]==Color) return false;
else if (c[i]== && !Dfs(i,-Color)) return false;
}
return true;
}
bool Work()
{
for (int i=;i<=n;i++)
{
if (vis[i]) continue;
if (!Dfs(i,i)) return false;
Cnt++;
for (int j=;j<=n;j++)
{
if (Abs(c[j])!=i) continue;
a[Cnt]+=(c[j]==i);
b[Cnt]+=(c[j]==-i);
}
}
return true;
}
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++)
{
while (true)
{
scanf("%d",&x); if (x==) break;
Tmp[i][x]=true;
}
}
for (int i=;i<=n;i++) for (int j=i+;j<=n;j++) if (!(Tmp[i][j]&&Tmp[j][i])) G[i][j]=G[j][i]=true;
if (!Work()) {puts("No solution"); return ;}
F[][]=;
for (int Op=;Op<=Cnt;Op++)
{
for (int i=n;i>=;i--) for (int j=n;j>=;j--)
{
if (i>=a[Op] && j>=b[Op] && F[i-a[Op]][j-b[Op]]) F[i][j]=true;
if (i>=b[Op] && j>=a[Op] && F[i-b[Op]][j-a[Op]]) F[i][j]=true;
}
}
Ans=;
for (int i=;i<=n;i++)
{
int j=n-i;
if (Abs(i-j)<Ans && F[i][j]) Ans=Abs(i-j);
}
printf("%d\n",Ans);
return ;
}

C++

LJOJ 1507

题目:RQNOJ P319

Sol: 可以计算出移动之后的Ans减少了Size[u]又增加加了Tot-Size[u],Dfs找到不能移动为止。

 #include <cstdio>
#include <cstring>
#define LL long long
const LL Maxn=;
struct EDGE{LL to,next;}edge[Maxn<<];
LL head[Maxn],Sum[Maxn],Dep[Maxn],Ans,n,l,r,w[Maxn],cnt,Tot;
inline void Add(LL u,LL v)
{edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
void Dfs(LL u,LL fa)
{
Sum[u]=w[u];
for (LL i=head[u];i!=-;i=edge[i].next)
{
if (edge[i].to==fa) continue;
Dep[edge[i].to]=Dep[u]+;
Dfs(edge[i].to,u);
Sum[u]+=Sum[edge[i].to];
}
}
void Find(LL u,LL fa)
{
for (LL i=head[u];i!=-;i=edge[i].next)
{
if (edge[i].to==fa) continue;
if (Tot-*Sum[edge[i].to]<)
{
Ans+=Tot-*Sum[edge[i].to];
Find(edge[i].to,u);
}
}
}
int main()
{
scanf("%lld",&n); memset(head,-,sizeof(head));
for (LL i=;i<=n;i++)
{
scanf("%lld%lld%lld",&w[i],&l,&r);
if (l) Add(i,l),Add(l,i);
if (r) Add(i,r),Add(r,i);
Tot+=w[i];
}
Dep[]=;
Dfs(,);
for (LL i=;i<=n;i++) Ans+=(Dep[i]-Dep[])*w[i];
Find(,);
printf("%lld\n",Ans);
return ;
}

C++

LJOJ 1508

题目:POJ 3694

Sol:求割点当且仅当 Low[v]>=Dfn[u]

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm];
int head[Maxn],Dfn[Maxn],Low[Maxn],Root,Son,u,v,n,cnt,Stamp;
bool Cut[Maxn];
inline int Min(int x,int y) {return x>y?y:x;}
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
void Tarjan(int u)
{
Dfn[u]=Low[u]=++Stamp;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (!Dfn[v])
{
Tarjan(v);
if (u==Root) Son++;
else
{
Low[u]=Min(Low[u],Low[v]);
if (Dfn[u]<=Low[v]) Cut[u]=true;
}
} else
Low[u]=Min(Low[u],Dfn[v]);
}
}
int main()
{
while (scanf("%d",&n)!=EOF && n!=)
{
memset(head,-,sizeof(head));
memset(Dfn,,sizeof(Dfn));
memset(Low,,sizeof(Low));
memset(Cut,false,sizeof(Cut)); Stamp=; cnt=;
while (scanf("%d",&u)!=EOF && u!=)
while (getchar()!='\n')
{
scanf("%d",&v);
Add(u,v),Add(v,u);
}
Root=,Son=;
Tarjan();
int Ans=;
if (Son>) Ans=;
for (int i=;i<=n;i++) if (Cut[i]) Ans++;
printf("%d\n",Ans);
}
return ;
}

C++

LJOJ 1509

题目:POJ 3177

Sol:Tarjan缩点之后找到桥的个数/2

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Maxm=;
struct EDGE{int to,next;}edge[Maxm<<];
int head[Maxn],Dfn[Maxn],Low[Maxn],vis[Maxn],n,m,u,v,cnt,Top,Stack[Maxn],d[Maxn],Scc,Stamp,Belong[Maxn],Ans;
inline void Add(int u,int v) {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
inline int Min(int x,int y) {return x>y?y:x;}
void Tarjan(int u,int fa)
{
Dfn[u]=Low[u]=++Stamp; Stack[++Top]=u; vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if (v==fa) continue;
if (!Dfn[v] && !vis[v])
{
Tarjan(v,u);
Low[u]=Min(Low[u],Low[v]);
} else if (vis[v]) Low[u]=Min(Low[u],Dfn[v]);
}
if (Dfn[u]==Low[u])
{
Scc++;
while (Stack[Top]!=u && Top>=) Belong[Stack[Top--]]=Scc;
Belong[Stack[Top--]]=Scc;
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
for (int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
Add(u,v),Add(v,u);
}
Tarjan(,);
for (int u=;u<=n;u++)
{
for (int i=head[u];i!=-;i=edge[i].next)
if (Belong[u]!=Belong[edge[i].to]) d[Belong[edge[i].to]]++;
} for (int i=;i<=Scc;i++) if (d[i]==) Ans++;
printf("%d\n",(Ans+)>>);
return ;
}

C++

LJOJ 1510

题目: BZOJ 1596

Sol: 树形DP

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=;
const int Inf=;
struct Node{int to,next;}edge[Maxn<<];
int F[Maxn][],cnt,n,u,v,head[Maxn];
bool vis[Maxn];
inline int Max(int x,int y) {return x>y?x:y;}
inline int Min(int x,int y) {return x>y?y:x;}
inline int Min3(int x,int y,int z) {return Min(x,Min(y,z));}
inline void Add(int u,int v)
{edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
void Dp(int u,int fa)
{
F[u][]=; F[u][]=; int Mx=-Inf;
for (int i=head[u];i!=-;i=edge[i].next)
{
if (fa==edge[i].to) continue;
Dp(edge[i].to,u);
F[u][]+=Min3(F[edge[i].to][],F[edge[i].to][],F[edge[i].to][]);
F[u][]+=Min(F[edge[i].to][],F[edge[i].to][]);
Mx=Max(Mx,Min(F[edge[i].to][],F[edge[i].to][])-F[edge[i].to][]);
F[u][]+=F[edge[i].to][];
}
F[u][]-=Mx;
}
int main()
{
scanf("%d",&n);
memset(head,-,sizeof(head));
for (int i=;i<n;i++) scanf("%d%d",&u,&v),Add(u,v),Add(v,u); Dp(,);
printf("%d\n",Min(F[][],F[][]));
return ;
}

C++

POJ 1274

二分图匹配

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
const int Maxn=;
int n,m,G[Maxn][Maxn],Link[Maxn],vis[Maxn],num,tmp;
bool Dfs(int u)
{
for (int i=;i<=m;i++)
if (G[u][i] && !vis[i])
{
vis[i]=true;
if (Link[i]==- || Dfs(Link[i]))
{
Link[i]=u;
return true;
}
}
return false;
}
int Hungary()
{
int Ret=;
memset(Link,-,sizeof(Link));
for (int i=;i<=n;i++)
{
for (int j=;j<=m;j++) vis[j]=false;
if (Dfs(i)) Ret++;
}
return Ret;
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(G,false,sizeof(G));
for (int i=;i<=n;i++)
{
scanf("%d",&num);
for (int j=;j<=num;j++)
{
scanf("%d",&tmp);
G[i][tmp]=true;
}
}
printf("%d\n",Hungary());
}
return ;
}

POJ 1274

BZOJ 3436

差分约束系统

a比b至少多c -> Add(a,b,-c)

a比b至多多c -> b比a至少多-c  Add(b,a,c);

a比b相等 ->Add(a,b,0)

加入满足所有要求则无负环

 #include <cstdio>
#include <cstring>
const int Inf=0x3f3f3f3f;
const int Maxn=;
struct EDGE{int to,next,w;}edge[Maxn<<];
int head[Maxn<<],n,m,vis[Maxn],Type,x,y,z,Dis[Maxn],flag,cnt;
inline void Add(int u,int v,int w)
{edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w;head[u]=cnt++;}
void Spfa(int u)
{
vis[u]=true;
for (int i=head[u];i!=-;i=edge[i].next)
if (Dis[edge[i].to]>Dis[u]+edge[i].w)
{
if (vis[edge[i].to])
{
flag=true;
break;
}
Dis[edge[i].to]=Dis[u]+edge[i].w;
Spfa(edge[i].to);
}
vis[u]=false;
} int main()
{ // freopen("c.in","r",stdin);
scanf("%d%d",&n,&m);
memset(head,-,sizeof(head));
for (int i=;i<=m;i++)
{
scanf("%d",&Type);
if (Type==)
{
scanf("%d%d%d",&x,&y,&z);
Add(x,y,-z);
}
if (Type==)
{
scanf("%d%d%d",&x,&y,&z);
Add(y,x,z);
}
if (Type==)
{
scanf("%d%d",&x,&y);
Add(x,y,);
}
}
for (int i=;i<=n;i++)
{
Dis[i]=;
Spfa(i);
}
if (flag) puts("No"); else puts("Yes");
return ;
}

BZOJ 3436

BZOJ 2068

拓扑排序,把所有入度为0的节点u加入对列,那么a[u]就是可以选择。再把a[a[u]]为0的加入

剩下的还有环就是环内总的节点数/2就可以了

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=;
int a[Maxn],In[Maxn],Q[Maxn],n,Ans;
bool vis[Maxn];
void Work()
{
int l=,r=;
for (int i=;i<=n;i++) if (In[i]==) Q[++r]=i,vis[i]=true;
while (l<=r)
{
int u=Q[l++];
if (!vis[a[u]])
{
Ans++,vis[a[u]]=true,In[a[a[u]]]--;
if (!vis[a[a[u]]] && In[a[a[u]]]==)
{
vis[a[a[u]]]=true;
Q[++r]=a[a[u]];
}
}
}
for (int i=;i<=n;i++)
if (!vis[i])
{
int t=i,Ret=;
while (!vis[t]) Ret++,vis[t]=true,t=a[t];
Ans+=(Ret>>);
}
}
int main()
{ scanf("%d",&n);
for (int i=;i<=n;i++)
{
scanf("%d",&a[i]);
In[a[i]]++;
}
Work();
printf("%d\n",Ans);
return ;
}

BZOJ 2068

BZOJ 1734 Floyd求最小环,就是多了一层对于已经得知道最短路,然后从后面的值开始Floyd

 #include <iostream>
#include <cstring>
#include <cstdio> using namespace std;
const int N=;
const int Inf=; int G[N][N],F[N][N],u,v,w;
int Road[N][N],Path[N]; int m,n,cnt,Ans; void Record(int s,int t)
{
if (Road[s][t])
{
Record(s,Road[s][t]);
Record(Road[s][t],t);
}
else Path[cnt++]=t;
} void Floyd()
{
Ans=Inf;
for (int k=;k<=n;k++)
{
for (int i=;i<k;i++)
for (int j=i+;j<k;j++)
if (Ans>F[i][j]+G[i][k]+G[k][j])
{
Ans=F[i][j]+G[i][k]+G[k][j];
cnt=;
Path[cnt++]=i;
Record(i,j);
Path[cnt++]=k;
}
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (F[i][j]>F[i][k]+F[k][j])
{
F[i][j]=F[i][k]+F[k][j];
Road[i][j]=k;
}
}
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
for (int i=;i<=n;i++)
for (int j=;j<=n;j++) F[i][j]=Inf,Road[i][j]=;
for (int i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
if (w<F[u][v]) F[u][v]=F[v][u]=w;
}
for (int i=;i<=n;i++)
for (int j=;j<=n;j++) G[i][j]=F[i][j];
Floyd();
if (Ans==Inf) puts("No solution.");
else
{
printf("%d",Path[]);
for (int i=;i<cnt;i++)
printf(" %d",Path[i]);
puts("");
}
}
return ;
}

BZOJ 1734

NOIP 考前 图论练习的更多相关文章

  1. NOIP考前划水

    NOIP考前划水 君指先跃动の光は.私の一生不変の信仰に.唯私の超電磁砲永世生き! 要开始背配置了? 3行不谢. (setq c-default-style "awk") (glo ...

  2. NOIP考纲总结+NOIP考前经验谈

    首先来一张图,很直观(截止到2012年数据) 下面是收集的一些,我改了一下 红色加粗表示特别重要,必须掌握 绿色加粗表示最好掌握,可能性不是很大,但是某些可以提高程序效率 高精度 a.加法 b.减法 ...

  3. NOIP考前知识点整理

    前言:距离NOIP还有不到一百天(虽然NOIP没了),为了整理一下所学的内容,才有了这篇博文.本文内容无特殊说明全部来自于博主的博客,代码也都是新敲的,努力在个人的码风基础上做到尽量简洁,求资瓷. 一 ...

  4. noip考前注意事项

    明天就要离开学校,后天的现在Day1已经考完啦,临近考试了紧不紧张呢(不紧张才怪),那么考前我们应该注意点什么呢? 1.带好自己的证件,带好自己的证件,带好自己的证件,这很重要. 2.试机的时候一定要 ...

  5. 2018 noip 考前临死挣扎

    基础算法 倍增 贪心 分块 二分 三分 数据结构 线段树 对顶堆 数学 质数 约数 同余 组合 矩阵乘法 图论 二分图判定以及最大匹配 字符串 Tire树 KMP 最小表示法 Hash Manache ...

  6. NOIP 考前研究

    NOIP 2017 试题研究 D1T1 小凯的疑惑 (45 min) 看到题面,大概是推数学公式. 先打暴力表,观察 \(a,b\) 与 \(n\) 的关系.猜想 \(a×b−a−b\). 引理:对于 ...

  7. 【NOIP考前模拟赛】纯数学方法推导——旅行者问题

    一.写在前面 这题似乎是一道原创题目(不是博主原创),所以并不能在任何OJ上评测,博主在网盘上上传了数据(网盘地址:http://pan.baidu.com/s/1mibdMXi),诸位看官需者自取. ...

  8. NOIP 考前 队列复习

    BZOJ 1127 #include <cstdio> #include <cstring> #include <iostream> #include <al ...

  9. NOIP 考前 数论复习

    POJ 2891 x=r1 (mod a1) x=r2 (mod a2) x=a1*x+r1,x=a2*y+r2; a1*x-a2*y=r2-r1; 用Extend_Gcd求出m1*x+m2*y=d; ...

随机推荐

  1. spring设置全局异常处理器

    1.spring设置全局异常,它的原理是向上捕获 spring.xml配置 <!--自定义全局异常处理器--> <bean id="globalExceptionResol ...

  2. The ProgID of the WorkspaceName's workspace factory

    The ProgID of the WorkspaceName's workspace factory [C#]public stringWorkspaceFactoryProgID {get; se ...

  3. Python基础笔记

    输入输出 输入input(),输入的字符以str作为结果,若要得到整数结果,需要进行数据类型转换,如a=int(input()). 输出print,格式化输出%s表示字符串替换,%d表示整数替换,%f ...

  4. Java: IO 学习小结

    源: 键盘 System.in 硬盘 FileStream 内存 ArrayStream 目的: 控制台 System.out 硬盘 FileStream 内存 ArrayStream 处理大文件或者 ...

  5. ie浏览器兼容问题汇总

    对兼容ie浏览器所遇到的问题及总结 互联快谈 2016-10-28 05:51 1,若直接给一个元素设置absolute定位.在浏览器缩放的时候.位置会错位.解决的方法是给外层的元素设置为relati ...

  6. Traveling in Blade & Soul

    Traveling in Blade & Soul Walking is too simple. Having trained their physics and spirits for ye ...

  7. linux下编译出现空间不足解决办法

    linux下编译出现空间不足解决办法 编译内核出现问题: AS      .tmp_kallsyms1.o .tmp_kallsyms1.S:2: fatal error: when writing ...

  8. Laravel框架 mysql 数据库 —— 基本使用

    增删改查 配置完数据库连接,就可以使用DB类进行查询了. 查询 $results = DB::select('select * from users where id = ?', array(1)); ...

  9. 百度echarts地图扩展动态加载geoCoord

    var data={}; for(var i=0;i<result.length;i++){ data[(""+result[i].name+"")]=e ...

  10. Swift 2.0 异常处理

    转自:http://www.jianshu.com/p/96a7db3fde00 WWDC 2015 宣布了新的 Swift 2.0. 这次重大更新给 Swift 提供了新的异常处理方法.这篇文章会主 ...