A 这个不等式组很眼熟吧
这道题的话上课讲过就是根据不等式建图然后跑一下最短路就可以了。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1005;
const int inf = 0x3f3f3f3f;
int dis[maxn];
int vis[maxn];
int head[maxn];
struct edge{
int to,w,next;
};
edge e[maxn];
void init(){
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
memset(dis,inf,sizeof(dis));
}
int spfa(int b,int n){
queue<int>q;
vis[b]=1;
dis[b]=0;
q.push(b);
while(!q.empty()){
int now=q.front();
q.pop();
vis[now]=0;
for(int i=head[now];i!=-1;i=e[i].next){
int v=e[i].to;
if(dis[v]>dis[now]+e[i].w){
dis[v]=dis[now]+e[i].w;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
return dis[n-1];
}
int main()
{
int n,m;
int cnt=0;
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[++cnt].to=a;
e[cnt].w=c;
e[cnt].next=head[b];
head[b]=cnt;
}
cout<<spfa(0,n)<<endl;
//for(int i=0;i<n;i++)
//cout<<dis[i]<<endl;
return 0;
}
B 牛也是有脾气的
这道题也是一个差分约束的题目,只是说的比较含蓄了一点,根据牛之间的关系就可以确定牛与牛之间的约束方程,根据约束方程建图跑最短路就可以了。
需要注意的是牛的位置坐标必须按他的序号依次排列所以每次建边的时候要注意牛的编号的大小再确定方向。
//差分约束+spfa
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1005;
const int inf =0x3f3f3f3f;
int vis[maxn];
int dis[maxn];
int visitcnt[maxn];
struct node{
int u,v,w,next;
};
int head[maxn];
node e[maxn*maxn];
void init(){
memset(visitcnt,0,sizeof(visitcnt));
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
memset(dis,inf,sizeof(dis));
}
int spfa(int n,int b){
queue<int>q;
dis[b]=0;
vis[b]=1;
q.push(b);
while(!q.empty()){
int now=q.front();
visitcnt[now]++;
if(visitcnt[now]>n){
return -1;
}
q.pop();
vis[now]=0;
for(int i=head[now];i!=-1;i=e[i].next){
int v=e[i].v;
if(dis[v]>dis[now]+e[i].w){
dis[v]=dis[now]+e[i].w;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
return dis[n];
}
int main()
{
int n,ml,md,cnt;
while(~scanf("%d %d %d",&n,&ml,&md)){
int a,b,c;
init();
cnt=0;
for(int i=0;i<ml;i++){
scanf("%d%d%d",&a,&b,&c);
int v=max(a,b);
int u=min(a,b);
e[++cnt].u=u;e[cnt].v=v;
e[cnt].w=c;e[cnt].next=head[a];
head[a]=cnt;
}
for(int i=0;i<md;i++){
scanf("%d%d%d",&a,&b,&c);
int u=max(a,b);
int v=min(a,b);
e[++cnt].u=u;e[cnt].v=v;
e[cnt].w=-c;e[cnt].next=head[b];
head[b]=cnt;
}
int ans=spfa(n,1);
if(ans==-1)printf("-1\n");
else if(ans==inf)printf("-2\n");
else printf("%d\n",ans);
}
return 0;
}
C 畅通工程
这道题大家前面应该做过,简单的并查集就可以搞定。
我主要是觉得会了并查集kruskal不在话下。
#include<iostream>
using namespace std;
int a[1005];
int main()
{
int Max;
int n,m;//城镇数n 道路数m
while(scanf("%d",&n)&&n!=0)
{
scanf("%d",&m);
int find(int x);
int i,j,t1,t2,r,s;
s=0;
for(i=1;i<=n;i++)
a[i]=i;
for(i=1;i<=m;i++)
{
scanf("%d %d",&t1,&t2);
if(find(t1)!=find(t2))
{
a[find(t1)]=find(t2);
}
}
for(i=1;i<=n;i++)
{
if(a[i]==i)
s++;
}
/* for(i=1;i<=n;i++)
{
printf("%d ",a[i]);
} */
printf("%d\n",s-1);
}
return 0;
}
int find(int x)
{
int r=x;
while(r!=a[r])
r=a[r];
return r;
}
D Jungle Roads
这道题是一道裸的最小生成树的题目 ,求出最小生成树即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 50;
const int maxv=2500;
int per[maxn];
struct edge{
int u,v,w;
}e[maxv];
bool compare(edge a,edge b){
return a.w<b.w;
}
int find(int x){
if(per[x]==x)return x;
per[x]=find(per[x]);
return per[x];
}
int join(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
per[fy]=fx;
return 1;
}
return 0;
}
int kruskal(int nn,int n){
int cont=0;
int ans=0;
for(int i=1;i<=nn;i++){
if(join(e[i].u,e[i].v)){
cont++;
ans+=e[i].w;
}
if(cont==n-1)break;
}
return ans;
}
int main()
{
int n;
while(scanf("%d",&n)&&n){
for(int i=0;i<maxn;i++){
per[i]=i;
}
char s[2];
int a;
int cnt=0;
for(int i=1;i<n;i++){
scanf("%s %d",s,&a);
for(int j=1;j<=a;j++){
int b;
scanf("%s %d",s,&b);
int uu=i;int vv=s[0]-'A'+1;
e[++cnt].u=uu;e[cnt].v=vv;
e[cnt].w=b;
e[++cnt].u=vv;e[cnt].v=uu;
e[cnt].w=b;
}
}
sort(e+1,e+1+cnt,compare);
int ans=kruskal(cnt,n);
printf("%d\n",ans);
}
}
E 千年老二
这是一道次小生成树的题目,在最小生成树的基础上加一些操作就好了。
注意次小生成树不存在的情况主是,可能这个图连最小生成树都没有,还有一种可能就是有两棵权值一样的最小生成树。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=0x3f3f3f3f;
int map[105][105];
int vis[105];
int dis[105];
int per[105];
int mapvis[105][105];
int max_ab[105][105];
int ans,ans1;
void init(){
for(int i=0;i<105;i++){
vis[i]=0;
for(int j=0;j<105;j++){
map[i][j]=maxn;
mapvis[i][j]=0;
}
}
ans=0;ans1=maxn;
}
void prim(int n){
vis[1]=1;
for(int i=1;i<=n;i++){
dis[i]=map[1][i];
per[i]=1;
}
for(int i=1;i<n;i++){
int minn=maxn,g;
for(int j=1;j<=n;j++){
if(!vis[j]&&minn>dis[j]){
minn=dis[j];
g=j;
}
}
ans+=minn;
vis[g]=1;
mapvis[g][per[g]]=mapvis[per[g]][g]=1;
for(int k=1;k<=n;k++){
if(vis[k]&&k!=g){
max_ab[k][g]=max_ab[g][k]=max(max_ab[per[g]][k],dis[g]);
}
if(!vis[k]){
if(map[g][k]<dis[k]){
dis[k]=map[g][k];
per[k]=g;
}
}
}
}
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
if(!mapvis[i][j]&&map[i][j]!=maxn){
ans1=min(ans+map[i][j]-max_ab[i][j],ans1);
}
}
}
}
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--){
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int xx,yy,vv;
scanf("%d%d%d",&xx,&yy,&vv);
map[xx][yy]=map[yy][xx]=vv;
}
prim(n);
if(ans==ans1||ans1==maxn)printf("-1\n");
else printf("%d\n",ans1);
}
}
F row也喜欢打算法比赛
这道题目就是简单的闭包传递,根据初始矩阵求出他的传递闭包就可以了。求出来之后我们可以根据每个点的出度和入度来判度这个点是否可以被准确定位。只要自己可以击败的人数和可以击败自己的人数加起来为n-1,就证明这个牛的位次是可以被确定的。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int mp[105][105];
int in[105];
int out[105];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(mp,0,sizeof(mp));
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
mp[a][b]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[j][i]){
for(int k=1;k<=n;k++){
mp[j][k]=mp[j][k]|mp[i][k];
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]){
out[i]++;
in[j]++;
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(in[i]+out[i]==n-1){
ans++;
}
}
cout<<ans<<endl;
}