标签:space name tchar src code node scanf second jks
给出一张有n个点和m条双向边的图,要求求出1到n的次短路的长度。一条边可以多次通过。
输入格式:
第一行为两个整数n和m。接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个点和他的长度。
输出格式:
一个整数,表示次短路的长度。
样例输入 |
样例输出 |
4 4 |
450 |
样例解释:
最短:1->2->4。
次短:1->2->3->4。
数据范围:
对于 100%的数据:1<=n、vi<=5000,1<=m<=100000。
solution: 裸的不能再裸的最短路,但用spfa会被卡,就上dij代码
#include<cstdio> #include<algorithm> #include<queue> #include<vector> using namespace std; const int maxn = 5000+100; const int inf = 0x7fffffff; typedef pair<int,int> P; struct edge{ int to,cost; }; vector<edge> G[maxn]; int n,m,ans; int dis1[maxn],disn[maxn]; void Dijkstra(int src,int dis[]) { priority_queue< P,vector<P>,greater<P> >que; dis[src]=0; que.push(P(dis[src],src)); while(!que.empty()){ P p=que.top(); que.pop(); int u=p.second,d=p.first; if(d>dis[u]) continue; for(int i=0;i<G[u].size();i++){ edge e=G[u][i]; if(e.cost+d<dis[e.to]){ dis[e.to]=d+e.cost; que.push(P(dis[e.to],e.to)); } } } } void solve() { fill(dis1+1,dis1+1+n,inf); fill(disn+1,disn+1+n,inf); Dijkstra(1,dis1); Dijkstra(n,disn); ans=0x7fffffff; for(int i=1;i<=n;i++) for(int j=0;j<G[i].size();j++){ int v=G[i][j].to,d=G[i][j].cost; if(dis1[i]+d+disn[v]>dis1[n]){ ans=min( ans , dis1[i]+ d + disn[v] ); } } } int main() { freopen("short.in","r",stdin); freopen("short.out","w",stdout); scanf("%d%d",&n,&m); int u,v,w; edge e; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); e.to=v,e.cost=w; G[u].push_back(e); e.to=u; G[v].push_back(e); } solve(); printf("%d\n",ans); return 0; }
LGL有一根长为n的木板。现在他想要把它砍成四段长度为整数的木板来做一个四边形,请问他有多少种不同的砍法?注意:四段长度为1、1、2、1和四段长度为1、2、1、1算两种砍法。
输入格式:
第一行为一个整数 n,表示木板的长度。
输出格式:
一个整数,不同的砍法数量。
样例输入 |
样例输出 |
6 |
6 |
样例解释:
1122,1212,1221,2112,2121,2211。
数据范围:
对于100%的数据:1<=n<=2500。
solution:
dp[i][j]表示长度为i时分成j段的方案数,随便转移。
这是正解,当然因为本题比较特殊,附上两个暴力代码。
正常暴力
#include<cstdio> using namespace std; int main() { freopen("quad.in","r",stdin); freopen("quad.out","w",stdout); long long t,n,sum=0; scanf("%lld",&n); for(long long i=1;i<=n-3;i++) for(long long j=1;j<n-i;j++) for(long long k=1;k<n-i-j;k++) { long long m=n-i-j-k; if((i+j+k>m)&&(i+k+m>j)&&(i+m+j>k)&&(k+m+j>i)) sum++; } printf("%lld\n",sum); }
优化暴力(from巨神lzb)
#include<cstdio> using namespace std; int main(){ freopen("bll.out","w",stdout); for(int n=0;n<=2500;n++){ long long ans=0; for(int i=1;i<=n/4;i++) for(int j=i;j<=(n-i)/3;j++) for(int k=j;k<=(n-i-j)/2;k++)if(n-i-j-k<i+j+k){ if(i==j&&j==k&&k==n-i-j-k)ans++; else if((i==j&&j==k)||(j==k&&k==n-i-j-k))ans+=4; else if(i==j&&k==n-i-j-k)ans+=6; else if(i==j||k==n-i-j-k||j==k)ans+=12; else ans+=24; } printf("%lld,",ans); } }
正解
#include <cstdio> #include <cstring> int n,mid; int dp[2501][5]; int getint() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-f; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘; ch=getchar(); } return x*f; } int min(int a,int b) { return a<b?a:b; } int main() { freopen("quad.in","r",stdin); freopen("quad.out","w",stdout); n=getint(); mid=(n-1)>>1; dp[0][0]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=4;j++) { for(int k=1;k<=min(mid,i);k++) dp[i][j]+=dp[i-k][j-1]; } } printf("%d",dp[n][4]); return 0; }
YYH有n道题要做。但是由于他上课做某些事,导致他一题都不会做,只好请LGL代打。LGL为了买自己心爱的坦克,他做第i题要收两笔钱:一笔在YYH叫他做题当天收,另外一笔在叫他做题的第二天收。YYH每天结束的时候都会把剩下的所有钱花光,然后再从父亲LRB处得到m元零花钱用来请LGL做题(也就是说,第一天的时候YYH是没有钱请LGL做题的,每一天用来请LGL做题所用的钱都是前一天LRB给的)。而且,YYH做的题目难度是循序渐进的:就算强如LGL,在做第i题之前也要先把第1到i-1题全部做完。请问YYH将所有题目做完并且把所有钱都付给LGL的最小天数。
输入格式:
第一行为两个整数m、n,接下来的n行每一行都有两个数ai和bi,分别表示LGL做第i题所收的两笔钱。
输出格式:
一个整数,表示最小天数。
样例输入 |
样例输出 |
100 5 |
6 |
样例解释:
第二天做1、2两题,第三天做3、4两题,第五天做5。在第六天的时候所有钱都付完。
数据范围:
对于100%的数据:1<=n<=300,1<=ai、bi<=m<=1000。
solution:dp[i][j]表示前i天做了j题后该天可能剩下的最多的钱的数量。那么dp[i][j]可以转移到dp[i][j+1]、dp[i][j+2]……只要满足剩下的钱不少于0并且下个月的钱够还即可。同时可以算出dp[i+1][j+1],dp[i+1][j+2]……最后输出满足dp[i][m]存在值的最小i。
#include <cstdio> #include <cstring> #define INF 0x3f3f3f3f int n,m,t1,t2; int a[301],b[301]; int dp[501][301]; int getint() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-f; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘; ch=getchar(); } return x*f; } int max(int a,int b) { return a>b?a:b; } int main() { freopen("solve.in","r",stdin); freopen("solve.out","w",stdout); n=getint(),m=getint(); for(int i=1;i<=m;i++) a[i]=getint(),b[i]=getint(); memset(dp,INF,sizeof(dp)); dp[2][0]=n; int i=2; while(dp[i][m]==INF) { for(int j=m;j>=0;j--) { if(dp[i][j]!=INF) { int k=j+1; t1=dp[i][j],t2=dp[i+1][j]=n; while(t1>=a[k]&&t2>=b[k]) { t1-=a[k]; t2-=b[k]; dp[i][k]=(dp[i][k]==INF?t1:max(dp[i][k],t1)); dp[i+1][k]=(dp[i+1][k]==INF?t2:max(dp[i+1][k],t2)); k++; } } } i++; } printf("%d",i); return 0; }
每天BBS都要从家里经过城市中的一段路到学校刷五三。城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口ai、bi且有一定的时间花费vi。BBS家编号为1,学校编号为n。今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0。现在他问你改变道路长度之后他到学校的最小时间花费是多少?
输入格式:
第一行为三个整数n、m、k,接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个路口和通过其所用的时间。
输出格式:
一个整数,表示BBS到学校的最小时间花费。
样例输入 |
样例输出 |
4 4 1 |
1 |
样例解释:
更新3->4的道路,最短路线为1->3->4,用时为1+0=1。
数据范围:
对于100%的数据:1<=n<=10000,1<=m<=50000,1<=k<=20,1<=vi<=1000000。
#include <cstdio> #include <cstring> #include <vector> #include <queue> #define INF 0x3f3f3f3f struct path { int to,v; }; struct node { int num,v; bool operator <(const node &b) const { return v>b.v; } }; std::vector<path> g[10001]; std::priority_queue<node> q; int m,n,k,ans; int dist[10001][21]; bool vis[10001][21]; int getint() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-f; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘; ch=getchar(); } return x*f; } int min(int a,int b) { return a<b?a:b; } void dij() { node now; memset(dist,INF,sizeof(dist)); memset(vis,false,sizeof(vis)); dist[1][0]=0; q.push((node){1,0}); while(!q.empty()) { now=q.top(); q.pop(); int t1=now.num%(n+1),t2=now.num/(n+1); vis[t1][t2]=true; for(int i=0;i<int(g[t1].size());i++) { path t=g[t1][i]; if((!vis[t.to][t2])&&dist[t.to][t2]>dist[t1][t2]+t.v) { dist[t.to][t2]=dist[t1][t2]+t.v; q.push((node){t2*(n+1)+t.to,dist[t.to][t2]}); } if((!vis[t.to][t2+1])&&t2<k&&dist[t.to][t2+1]>dist[t1][t2]) { dist[t.to][t2+1]=dist[t1][t2]; q.push((node){(t2+1)*(n+1)+t.to,dist[t.to][t2+1]}); } } } } int main() { freopen("school.in","r",stdin); freopen("school.out","w",stdout); n=getint(),m=getint(),k=getint(); for(int i=1;i<=m;i++) { int a=getint(),b=getint(),v=getint(); g[a].push_back((path){b,v}); g[b].push_back((path){a,v}); } dij(); ans=INF; for(int i=0;i<=k;i++) ans=min(ans,dist[n][i]); printf("%d",ans); return 0; }
标签:space name tchar src code node scanf second jks
原文地址:http://www.cnblogs.com/qizhengquan/p/7592837.html