#include "bits/stdc++.h"
using namespace std;

#pragma GCC optimize("O3","unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC target("avx2")
#define sync ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define all(x) x.begin(),x.end()
#define unq(a) sort(all(a));a.resize(unique(all(a)) - a.begin())
#define ll long long
#define ld long double
#define pb push_back
#define fi first
#define se second
#define endl '\n'
const int mxn = 3e5 + 3;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int n, m, k;
struct SSC{
    vector<vector<int>> arcs,metaArcs,metaTopo; // input arcs , meta-arcs and Toposort of metagraph 
    int vertex_count,mnode_count; // total vertices and #metanodes(after extraction)
    vector<int> metaID,idtopo;// id[a] = X, means a belongs to meta node X and idtopo : toposort of ssc {id / mnode}
    vector<bool> visited;
    vector<long long> lowlink;
    vector<int> stk,indeg,intime;
    int tptr = 0;
    // 1 indexed node names
    SSC(int n = 0){
        vertex_count = n;
        arcs.clear();
        arcs.resize(vertex_count + 1);
        metaTopo.clear();metaArcs.clear();
        mnode_count = 0;
        metaID.clear();idtopo.clear();
    }

    void inline resize(int n){
        vertex_count = n;
        arcs.clear();
        arcs.resize(vertex_count + 1);
        metaTopo.clear();metaArcs.clear();
        mnode_count = 0;
        metaID.clear();idtopo.clear();
    }

    void inline addEdge(int u,int v){
        //assert(u >= 1 && u <= vertex_count);
        //assert(v >= 1 && v <= vertex_count);
        arcs[u].push_back(v);
    }

    void dfs(int curr,int par){
        intime[curr] = ++tptr;// else we can use depth as a parameter
        lowlink[curr] = intime[curr];
        stk.push_back(curr);
        visited[curr] = true;

        for (int& to : arcs[curr]){
            if (visited[to] == false){
                dfs(to ,curr);
            }
            lowlink[curr] = min(lowlink[curr] , lowlink[to]);// (back) or (back of frwd). cross edge is redundant
        }
        if (lowlink[curr] == intime[curr]){
            mnode_count++;
            vector<int> ssc;
            while(true){
                //assert(stk.size());
                int ver = stk.back();
                stk.pop_back();
                metaID[ver] = mnode_count;
                ssc.push_back(ver);
                lowlink[ver] = 1e15; // reset so that cross edge case is covered
                if (ver == curr)
                    break;
            }
            metaTopo.push_back(ssc);
            idtopo.push_back(mnode_count);
        }
    }

    void ApplyTarjan(){
        visited.clear();visited.resize(vertex_count + 1);
        lowlink.clear();lowlink.resize(vertex_count + 1,1e15);
        stk.clear();
        intime.clear();intime.resize(vertex_count + 1);
        tptr = mnode_count = 0; 
        for (int ver = 1;ver <= vertex_count;ver++){
            if (visited[ver]) continue;
            dfs(ver,0);
            assert(stk.size() == 0);
        }
        // One of the Toposort is just reverse of the order we got
        reverse(idtopo.begin() , idtopo.end());
        reverse(metaTopo.begin() , metaTopo.end());
        
    }
    void inline extract_scc(){
        //assert(vertex_count);//err else null 
        metaID.clear();metaID.resize(vertex_count + 1,-1);
        metaTopo.clear();idtopo.clear();
        ApplyTarjan();
    }
    // Note : Resulting meta graph will always be a DAG (Directed Acyclic Graph)
    void generate_marcs(){
        //assert(mnode_count);// mnodes must have been extracted before hand
        metaArcs.clear();
        metaArcs.resize(mnode_count + 1);
        // Note : remove or handle multiple edges / parallel between metanodes correctly
        for (int ver = 1;ver <= vertex_count;ver++){
            for (int& to : arcs[ver]){
                if (metaID[ver] == metaID[to]) continue;
                metaArcs[metaID[ver]].push_back(metaID[to]);
            }
        }
        for (int mver = 1;mver <= mnode_count;mver++){
            unq(metaArcs[mver]);
        }
    }
    int min_edge_add(){
        // Minimum required arcs to make the given "directed graph" a strongly connected graph
        assert(mnode_count);
        int sink_cnt = 0,src_cnt = 0;
        vector<int> in(mnode_count + 1),out(mnode_count + 1);
        for (int mver = 1;mver <= mnode_count;mver++){
            for (int &mto : metaArcs[mver]){
                in[mto]++;
                out[mver]++;
            }
        }
        for (int mver = 1;mver <= mnode_count;mver++){
            src_cnt += (in[mver] ? 0 : 1);
            sink_cnt += (out[mver] ? 0 : 1);
        }
        return max(src_cnt , sink_cnt);
    }
};

int main(){
    
    #ifndef ONLINE_JUDGE 
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif

    sync

    

    int t = 1; 
    //cin >> t;
    while(t--){
        cin >> n >> m >> k;

        vector<string> pat(n), s(m);
        vector<int> idx(m);
        map<string , int> inpat;
        for (int i = 0;i < n;i++){
            cin >> pat[i];
            inpat[pat[i]] = i;
        }

        bool ok = 1;
        string str;

        SSC dg(n);

        for (int i = 0;i < m;i++){
            cin >> s[i] >> idx[i];
            idx[i]--;

            bool go = 0;
            if (ok){
                string& mk = pat[idx[i]];
                for (int j = 0;j < (1 << k); j++){
                    str = "";
                    for (int z = 0; z < k; z++){
                        if (j & (1 << z)){
                            str += s[i][z];
                        }
                        else{
                            str += '_';
                        }
                    }
                    if (str != mk){
                        if (inpat.count(str)){
                            dg.addEdge(idx[i] + 1, inpat[str] + 1);
                        }
                    }
                    else{
                        go = 1;
                    }
                }
            }
            if (!go){
                ok = false;
            }
        }

        dg.extract_scc();
        dg.generate_marcs();

        ok &= (dg.metaTopo.size() == n);
        if (ok){
            cout << "YES" << endl;
            for (auto v : dg.metaTopo){
                cout << v[0] << " ";
            } cout << endl;
        }
        else{
            cout << "NO" << endl;
        }
    }

    cerr << "processor time: " << clock() / (double) CLOCKS_PER_SEC << "s    ";
    return 0;
}