[ Google APAC 2015 University Graduates Test ] Round C APAC Test
题目链接:
http://code.google.com/codejam/contest/5214486/dashboard
Problem A. Minesweeper
题目意思:
扫雷。告诉地雷所在的位置,求至少须要几步,把全部的非雷位置都翻过来。假设某一个格子周围都不是地雷。则翻转该格子会把周围的格子都翻转过来。
解题思路:
dfs找连通块
先把非雷格子周围的地雷总数求出,然后对于周围没有地雷的格子找连通块。剩下的每一个格子都须要再翻转一次。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 330 char sa[Maxn][Maxn]; int nu[Maxn][Maxn]; bool vis[Maxn][Maxn]; int n,ans; int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}}; bool iscan(int x,int y) { if(x<1||x>n||y<1||y>n) return false; return true; } void dfs(int x,int y) { for(int i=0;i<8;i++) { int xx=x+dir[i][0],yy=y+dir[i][1]; if(!iscan(xx,yy)||vis[xx][yy]) continue; ans++; vis[xx][yy]=true; if(!nu[xx][yy]) dfs(xx,yy); } } int main() { freopen("A-large.in","r",stdin); freopen("A-large.out","w",stdout); int t,cas=0; scanf("%d",&t); while(t--) { scanf("%d",&n); int cnt=0; for(int i=1;i<=n;i++) { scanf("%s",sa[i]+1); for(int j=1;j<=n;j++) if(sa[i][j]=='.') cnt++; } memset(nu,0,sizeof(nu)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(sa[i][j]=='.') continue; for(int k=0;k<8;k++) { int x=i+dir[k][0],y=j+dir[k][1]; if(!iscan(x,y)||sa[x][y]=='*') continue; nu[x][y]++; } } } memset(vis,false,sizeof(vis)); ans=0; int temp=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(sa[i][j]=='*') continue; if(!nu[i][j]&&!vis[i][j]) { vis[i][j]=true; temp++; ans++; dfs(i,j); } } //printf("ans:%d cnt:%d\n",ans,cnt); printf("Case #%d: %d\n",++cas,cnt-ans+temp); } return 0; }
题目意思:
有n号地铁线,每号地铁线有Sni个站,告诉地铁经过每号线相邻两站的花费时间。有m个换乘点,每一个换乘点连接两个不同的地铁线路两站,告诉每一个换乘点的花费时间。当到达某号线的某个网站时,假设要乘该号线,须要等待该号线所需时间。
解题思路:
BFS【最短路】
此题难点就是假设恰好要乘某号线时,要等待该号线的时间。不优点理。
把每一个站看成点,把点翻倍,如果总共同拥有li个点。
A点表示已经在乘该站所在的那号线喽,等待时间已经计算好了。A+li表示刚到该站,还没等该号线所需等待时间。要分开处理,不然不好转移。从li+A到A须要花费等待的时间,从A到li+A则不须要。
对于换乘点。要么刚乘车到A,换成到B+li.要么从li+A换乘到li+B.
注意全部的边都是双向的。
最后求出li+s到li+e就可以。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 210000 struct Edge { int to,add,ti; Edge(int a,int b,int c) { to=a,ti=b,add=c; } }; vector<vector<Edge> >myv; int sum[110],cn[110],ct[110],n,m,q; bool vis[Maxn]; struct Node { int hav,id,wai; Node(){} Node(int a,int b,int c) { hav=a,id=b,wai=c; } friend bool operator <(Node a,Node b) { return a.hav>b.hav; } }; int bfs(int s,int e) { priority_queue<Node>myq; myq.push(Node(0,s,-1)); while(!myq.empty()) { Node now=myq.top(); //printf("id:%d hav:%d\n",now.id,now.hav); //system("pause"); if(now.id==e) return now.hav; myq.pop(); if(vis[now.id]) continue; vis[now.id]=true; for(int i=0;i<myv[now.id].size();i++) { int ne=myv[now.id][i].to; Node nex; if(vis[ne]) continue; nex.hav=now.hav+myv[now.id][i].ti; nex.id=ne; myq.push(nex); } } return -1; } int main() { //freopen("B-large-practice.in","r",stdin); //freopen("B-large-practice.out","w",stdout); int t,cas=0; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); memset(sum,0,sizeof(sum)); myv.clear(); myv.resize(n*2050); for(int i=1;i<=n;i++) { scanf("%d%d",&cn[i],&ct[i]); for(int j=1;j<cn[i];j++) { int ti; scanf("%d",&ti); int a=sum[i-1]+j,b=sum[i-1]+j+1; myv[a].push_back(Edge(b,ti,i)); myv[b].push_back(Edge(a,ti,i)); } sum[i]=sum[i-1]+cn[i]; } int li=sum[n]; for(int i=1;i<=n;i++) { int a=sum[i-1],b=sum[i]; for(int j=a+1;j<=b;j++) { myv[li+j].push_back(Edge(j,ct[i],-1)); myv[j].push_back(Edge(li+j,0,-1)); } } scanf("%d",&m); for(int i=1;i<=m;i++) { int a1,b1,a2,b2,c; scanf("%d%d%d%d%d",&a1,&b1,&a2,&b2,&c); myv[li+sum[a1-1]+b1].push_back(Edge(li+sum[a2-1]+b2,c,-1)); myv[sum[a1-1]+b1].push_back(Edge(li+sum[a2-1]+b2,c,-1)); myv[li+sum[a2-1]+b2].push_back(Edge(li+sum[a1-1]+b1,c,-1)); myv[sum[a2-1]+b2].push_back(Edge(li+sum[a1-1]+b1,c,-1)); } scanf("%d",&q); printf("Case #%d:\n",++cas); for(int i=1;i<=q;i++) { int a1,b1,a2,b2; scanf("%d%d%d%d",&a1,&b1,&a2,&b2); memset(vis,false,sizeof(vis)); int temp1=bfs(li+sum[a1-1]+b1,li+sum[a2-1]+b2); //memset(vis,false,sizeof(vis)); //int temp2=bfs(sum[a2-1]+b2,sum[a1-1]+b1); printf("%d\n",temp1);//min(temp1,temp2)); } } return 0; } /* 10 2 3 5 3 4 3 6 1 2 2 1 2 2 2 9 2 2 1 2 8 1 1 1 2 3 24 */
Problem C. Broken Calculator
题目意思:
一个坏的计算器有些数字button不能用。运算符仅仅能用*和=,给定一个数x,求得到x所需的最少的按键步数。否则直接输出-1.
解题思路:
记忆话搜索
由于仅仅有一个乘运算,所以枚举n的约数i,假设得到i的最少次数没有计算。则先计算得到i的最少次数,方式和计算n是一样的。
再以相同方式计算n/i,然后更新n的最少次数min(nu[i]+nu[n/i]+1),+1表示乘号。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1100000 int nu[Maxn]; int hav[12]; int iscan(int x) { int res=0; while(x) { if(!hav[x%10]) return -1; x/=10; res++; } return res; } int dfs(int cur) { if(nu[cur]!=-1) return nu[cur]; int temp=iscan(cur); if(temp!=-1) nu[cur]=temp; else nu[cur]=INF; for(int i=1;i*i<=cur;i++) { if(cur%i==0) { int t1=dfs(i); int t2=dfs(cur/i); nu[cur]=min(nu[cur],t1+t2+1); } } return nu[cur]; } int main() { freopen("C-large-practice.in","r",stdin); freopen("C-large-practice.out","w",stdout); int t,cas=0,n; scanf("%d",&t); while(t--) { for(int i=0;i<10;i++) scanf("%d",&hav[i]); scanf("%d",&n); memset(nu,-1,sizeof(nu)); nu[n]=dfs(n); if(nu[n]==INF) printf("Case #%d: Impossible\n",++cas); else printf("Case #%d: %d\n",++cas,nu[n]+1); } return 0; }